pygit2_refdb_backend_lookup() never releases the Reference object returned by the Python lookup callback, leaking one object per call. Correcting the leakcalso requires duplicating the underlying git_reference, because the raw pointer is currently borrowed from the leaked Python object.
File: src/refdb_backend.c
Function: pygit2_refdb_backend_lookup
Relevant code:
result = (Reference *)PyObject_CallObject(be->lookup, args);
Py_DECREF(args);
if ((err = git_error_for_exc()) != 0)
goto out;
if (!PyObject_IsInstance((PyObject *)result, (PyObject *)&ReferenceType)) {
PyErr_SetString(PyExc_TypeError, "Expected object of type pygit2.Reference");
err = GIT_EUSER;
goto out;
}
*out = result->reference;
out:
return err;
PyObject_CallObject() returns a new reference, but result is never decrefed on any path, so the Python Reference leaks on every successful lookup.
Note that simply adding Py_DECREF(result) is not sufficient: *out = result->reference borrows the inner git_reference *, and the Reference object owns it (its dealloc frees it). Releasing result without duplicating the reference would leave *out dangling — a use-after-free. The sibling pygit2_refdb_backend_rename() handles this correctly with git_reference_dup(out, ref->reference) before Py_DECREF(ref).
Suggested fix:
git_reference_dup(out, result->reference);
Py_DECREF(result);
out:
Py_XDECREF(result); /* release on the error paths too */
return err;
(Or restructure so result is decrefed on every path while *out is set only via git_reference_dup.)
pygit2_refdb_backend_lookup()never releases theReferenceobject returned by the Pythonlookupcallback, leaking one object per call. Correcting the leakcalso requires duplicating the underlyinggit_reference, because the raw pointer is currently borrowed from the leaked Python object.File:
src/refdb_backend.cFunction:
pygit2_refdb_backend_lookupRelevant code:
PyObject_CallObject()returns a new reference, butresultis never decrefed on any path, so the PythonReferenceleaks on every successful lookup.Note that simply adding
Py_DECREF(result)is not sufficient:*out = result->referenceborrows the innergit_reference *, and theReferenceobject owns it (its dealloc frees it). Releasingresultwithout duplicating the reference would leave*outdangling — a use-after-free. The siblingpygit2_refdb_backend_rename()handles this correctly withgit_reference_dup(out, ref->reference)beforePy_DECREF(ref).Suggested fix:
(Or restructure so
resultis decrefed on every path while*outis set only viagit_reference_dup.)