Double DECREF / use-after-free in `pygit2_refdb_backend_write` · Issue #1471 · libgit2/pygit2 · GitHub
Skip to content

Double DECREF / use-after-free in pygit2_refdb_backend_write #1471

Closed

Description

@K-ANOY

pygit2_refdb_backend_write() passes owned objects to Py_BuildValue() with the N format (which steals the reference), then decrefs the same objects again in its cleanup block — a double DECREF that can lead to a use-after-free.

File: src/refdb_backend.c

Function: pygit2_refdb_backend_write

Relevant code:

PyObject *args = NULL, *ref = NULL, *who = NULL, *old = NULL;

if ((ref = wrap_reference((git_reference *)_ref, NULL)) == NULL)
    goto euser;
if ((who = build_signature(NULL, _who, "utf-8")) == NULL)
    goto euser;
if ((old = git_oid_to_python(_old)) == NULL)
    goto euser;
if ((args = Py_BuildValue("(NNNsNs)", ref,
        force ? Py_True : Py_False,
        who, message, old, old_target)) == NULL)
    goto euser;

PyObject_CallObject(be->write, args);
err = git_error_for_exc();
out:
    Py_DECREF(ref);
    Py_DECREF(who);
    Py_DECREF(old);
    Py_DECREF(args);
    return err;
euser:
    err = GIT_EUSER;
    goto out;

Three problems:

  1. Double DECREF. The N format steals a reference, so on success ref, who, and old are owned by the tuple args. The out: block then calls Py_DECREF(ref), Py_DECREF(who), Py_DECREF(old) and Py_DECREF(args) (which decrefs each element again during tuple deallocation). Each of the three objects is released one time too many.

  2. Stolen singleton. force ? Py_True : Py_False is a borrowed singleton reference. Passing it with N (without Py_INCREF) transfers a reference the function never owned, underflowing the singleton's refcount.

  3. Non-X cleanup on the error path. All four locals are initialized to NULL, but the euser path jumps to out:, which uses Py_DECREF rather than Py_XDECREF. If an early allocation fails (e.g. wrap_reference returns NULL), the cleanup dereferences a NULL pointer and crashes instead of returning GIT_EUSER.

Activity

  1. added a commit that references this issue on Sep 27, 2026
    eb512d2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions