pygit2_refdb_backend_exists() unconditionally decrefs the callback result in a shared cleanup block, but on the error path that result is NULL, so a raising exists callback causes Py_DECREF(NULL) and crashes the interpreter.
File: src/refdb_backend.c
Function: pygit2_refdb_backend_exists
Relevant code:
result = PyObject_CallObject(be->exists, args);
Py_DECREF(args);
if ((err = git_error_for_exc()) != 0)
goto out;
*exists = PyObject_IsTrue(result);
out:
Py_DECREF(result);
return 0;
If the Python exists callback raises, PyObject_CallObject() returns NULL, git_error_for_exc() is non-zero, and control jumps to out:, where Py_DECREF(result) dereferences a NULL pointer.
Suggested fix: use Py_XDECREF (and propagate err):
out:
Py_XDECREF(result);
return err;
The related boolean callbacks pygit2_refdb_backend_has_log() and pygit2_refdb_backend_ensure_log() have the mirror-image shape — they return err on the error path without releasing result. In practice result is NULL there whenever an error is set, so it is only a theoretical leak, but for robustness they should Py_XDECREF(result) before returning as well.
pygit2_refdb_backend_exists()unconditionally decrefs the callback result in a shared cleanup block, but on the error path that result isNULL, so a raisingexistscallback causesPy_DECREF(NULL)and crashes the interpreter.File:
src/refdb_backend.cFunction:
pygit2_refdb_backend_existsRelevant code:
If the Python
existscallback raises,PyObject_CallObject()returnsNULL,git_error_for_exc()is non-zero, and control jumps toout:, wherePy_DECREF(result)dereferences aNULLpointer.Suggested fix: use
Py_XDECREF(and propagateerr):The related boolean callbacks
pygit2_refdb_backend_has_log()andpygit2_refdb_backend_ensure_log()have the mirror-image shape — theyreturn erron the error path without releasingresult. In practiceresultisNULLthere whenever an error is set, so it is only a theoretical leak, but for robustness they shouldPy_XDECREF(result)before returning as well.