Skip to content

gh-127314: Don't mention the GIL when calling without a thread state on the free-threaded build #127315

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Dec 6, 2024
7 changes: 7 additions & 0 deletions Include/internal/pycore_pystate.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,10 +190,17 @@ static inline void
_Py_EnsureFuncTstateNotNULL(const char *func, PyThreadState *tstate)
{
if (tstate == NULL) {
#ifndef Py_GIL_DISABLED
_Py_FatalErrorFunc(func,
"the function must be called with the GIL held, "
"after Python initialization and before Python finalization, "
"but the GIL is released (the current Python thread state is NULL)");
#else
_Py_FatalErrorFunc(func,
"the function must be called with an active thread state, "
"after Python initialization and before Python finalization, but it is NULL "
"(are you trying to call the C API inside of a Py_BEGIN_ALLOW_THREADS block?)");
#endif
}
}

Expand Down
9 changes: 7 additions & 2 deletions Lib/test/test_capi/test_mem.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,13 @@ def test_api_misuse(self):

def check_malloc_without_gil(self, code):
out = self.check(code)
expected = ('Fatal Python error: _PyMem_DebugMalloc: '
'Python memory allocator called without holding the GIL')
if not support.Py_GIL_DISABLED:
expected = ('Fatal Python error: _PyMem_DebugMalloc: '
'Python memory allocator called without holding the GIL')
else:
expected = ('Fatal Python error: _PyMem_DebugMalloc: '
'Python memory allocator called without an active thread state. '
'(Are you trying to call it inside of a Py_BEGIN_ALLOW_THREADS block?)')
self.assertIn(expected, out)

def test_pymem_malloc_without_gil(self):
Expand Down
16 changes: 11 additions & 5 deletions Lib/test/test_capi/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,17 @@ def test_no_FatalError_infinite_loop(self):
_rc, out, err = run_result
self.assertEqual(out, b'')
# This used to cause an infinite loop.
msg = ("Fatal Python error: PyThreadState_Get: "
"the function must be called with the GIL held, "
"after Python initialization and before Python finalization, "
"but the GIL is released "
"(the current Python thread state is NULL)").encode()
if not support.Py_GIL_DISABLED:
msg = ("Fatal Python error: PyThreadState_Get: "
"the function must be called with the GIL held, "
"after Python initialization and before Python finalization, "
"but the GIL is released "
"(the current Python thread state is NULL)").encode()
else:
msg = ("Fatal Python error: PyThreadState_Get: "
"the function must be called with an active thread state, "
"after Python initialization and before Python finalization, but it is NULL "
"(are you trying to call the C API inside of a Py_BEGIN_ALLOW_THREADS block?)").encode()
self.assertTrue(err.rstrip().startswith(msg),
err)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Improve error message when calling the C API without an active thread state
on the :term:`free-threaded <free threading>` build.
7 changes: 7 additions & 0 deletions Objects/obmalloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -2910,9 +2910,16 @@ static inline void
_PyMem_DebugCheckGIL(const char *func)
{
if (!PyGILState_Check()) {
#ifndef Py_GIL_DISABLED
_Py_FatalErrorFunc(func,
"Python memory allocator called "
"without holding the GIL");
#else
_Py_FatalErrorFunc(func,
"Python memory allocator called "
"without an active thread state. "
"(Are you trying to call it inside of a Py_BEGIN_ALLOW_THREADS block?)");
#endif
}
}

Expand Down
Loading