Skip to content

OdbBackend: acquire the GIL in the callbacks, fix write_cb's type argument - #1496

Merged
jdavid merged 2 commits into
libgit2:masterfrom
cboos:odb-backend-gil
Sep 19, 2026
Merged

jdavid merged 2 commits into
libgit2:masterfrom
cboos:odb-backend-gil

Conversation

@cboos

@cboos cboos commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

With an OdbBackend implemented in Python, Index.add(path) crashes the interpreter (access violation on Windows, Python 3.13, pygit2 1.20.1), single-threaded.

Cause: the odb backend callbacks in src/odb_backend.c call into Python without holding the GIL. That works when libgit2 is entered from the C extension, which keeps the GIL, but cffi releases it around every C call, so git_index_add_bypath reaches the callbacks without it.

Fix: PyGILState_Ensure/PyGILState_Release in each callback, the same pattern as in src/filter.c. It is re-entrant, so it is fine when the caller already holds the GIL.

Second commit: write_cb received its type argument through the n format (Py_ssize_t) though git_object_t is an int; on 64-bit Windows it got e.g. 2753074036739 instead of 3 for a blob. It is now passed as i.

Tests: test_index_add (run in a subprocess, since the failure is a crash) and test_write_cb. Both fail before and pass after, on Windows x64 with MSVC, CPython 3.13 and libgit2 1.9.7; the full suite passes with the first commit.

Not done here: src/refdb_backend.c has the same missing GIL. Possibly related: #1004.


This PR (analysis, patch, tests and this description) was prepared by Claude Fable 5.1, working for @cboos.

🤖 Generated with Claude Code

The callbacks libgit2 calls for an OdbBackend implemented in Python
called into Python without holding the GIL. That works when libgit2 is
entered from the C extension, which keeps the GIL, but not from cffi,
which releases it around every C call: Index.add on a repository with
such a backend crashes the interpreter (access violation on Windows).

Acquire the GIL with PyGILState_Ensure, like the filter callbacks do.

Assisted-by: Claude Fable 5.1
The type was passed to PyObject_CallMethod with the "n" format, which
reads a Py_ssize_t, but git_object_t is an int. On 64-bit Windows
write_cb received garbage in the upper 32 bits, e.g. 2753074036739
(0x28100000003) instead of 3 for a blob.

Assisted-by: Claude Fable 5.1
@jdavid
jdavid merged commit 663d3d7 into libgit2:master Sep 19, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants