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

Co-authored-by: Victor Stinner <vstinner@python.org>
This commit is contained in:
Peter Bierma 2024-12-06 10:58:19 -05:00 committed by GitHub
parent a353455fca
commit 12680ec5bd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 36 additions and 7 deletions

View file

@ -190,10 +190,18 @@ static inline void
_Py_EnsureFuncTstateNotNULL(const char *func, PyThreadState *tstate) _Py_EnsureFuncTstateNotNULL(const char *func, PyThreadState *tstate)
{ {
if (tstate == NULL) { if (tstate == NULL) {
#ifndef Py_GIL_DISABLED
_Py_FatalErrorFunc(func, _Py_FatalErrorFunc(func,
"the function must be called with the GIL held, " "the function must be called with the GIL held, "
"after Python initialization and before Python finalization, " "after Python initialization and before Python finalization, "
"but the GIL is released (the current Python thread state is NULL)"); "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 was called without an active thread state. "
"Are you trying to call the C API inside of a Py_BEGIN_ALLOW_THREADS block?");
#endif
} }
} }

View file

@ -68,8 +68,13 @@ class PyMemDebugTests(unittest.TestCase):
def check_malloc_without_gil(self, code): def check_malloc_without_gil(self, code):
out = self.check(code) out = self.check(code)
expected = ('Fatal Python error: _PyMem_DebugMalloc: ' if not support.Py_GIL_DISABLED:
'Python memory allocator called without holding the GIL') 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) self.assertIn(expected, out)
def test_pymem_malloc_without_gil(self): def test_pymem_malloc_without_gil(self):

View file

@ -100,11 +100,18 @@ class CAPITest(unittest.TestCase):
_rc, out, err = run_result _rc, out, err = run_result
self.assertEqual(out, b'') self.assertEqual(out, b'')
# This used to cause an infinite loop. # This used to cause an infinite loop.
msg = ("Fatal Python error: PyThreadState_Get: " if not support.Py_GIL_DISABLED:
"the function must be called with the GIL held, " msg = ("Fatal Python error: PyThreadState_Get: "
"after Python initialization and before Python finalization, " "the function must be called with the GIL held, "
"but the GIL is released " "after Python initialization and before Python finalization, "
"(the current Python thread state is NULL)").encode() "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 was called without an active thread state. "
"Are you trying to call the C API inside of a Py_BEGIN_ALLOW_THREADS block?").encode()
self.assertTrue(err.rstrip().startswith(msg), self.assertTrue(err.rstrip().startswith(msg),
err) err)

View file

@ -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.

View file

@ -2910,9 +2910,16 @@ static inline void
_PyMem_DebugCheckGIL(const char *func) _PyMem_DebugCheckGIL(const char *func)
{ {
if (!PyGILState_Check()) { if (!PyGILState_Check()) {
#ifndef Py_GIL_DISABLED
_Py_FatalErrorFunc(func, _Py_FatalErrorFunc(func,
"Python memory allocator called " "Python memory allocator called "
"without holding the GIL"); "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
} }
} }