Skip to content

Commit 3026cad

Browse files
authored
bpo-40826: Add _Py_EnsureTstateNotNULL() macro (GH-20571)
Add _Py_EnsureTstateNotNULL(tstate) macro: call Py_FatalError() if tstate is NULL, the error message contains the current function name.
1 parent db64f12 commit 3026cad

File tree

6 files changed

+40
-31
lines changed

6 files changed

+40
-31
lines changed

Include/internal/pycore_pystate.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,21 @@ _PyThreadState_GET(void)
8686
#undef PyThreadState_GET
8787
#define PyThreadState_GET() _PyThreadState_GET()
8888

89+
PyAPI_FUNC(void) _Py_NO_RETURN _Py_FatalError_TstateNULL(const char *func);
90+
91+
static inline void
92+
_Py_EnsureFuncTstateNotNULL(const char *func, PyThreadState *tstate)
93+
{
94+
if (tstate == NULL) {
95+
_Py_FatalError_TstateNULL(func);
96+
}
97+
}
98+
99+
// Call Py_FatalError() if tstate is NULL
100+
#define _Py_EnsureTstateNotNULL(tstate) \
101+
_Py_EnsureFuncTstateNotNULL(__func__, tstate)
102+
103+
89104
/* Get the current interpreter state.
90105
91106
The macro is unsafe: it does not check for error and it can return NULL.
@@ -96,7 +111,9 @@ _PyThreadState_GET(void)
96111
and _PyGILState_GetInterpreterStateUnsafe(). */
97112
static inline PyInterpreterState* _PyInterpreterState_GET(void) {
98113
PyThreadState *tstate = _PyThreadState_GET();
99-
assert(tstate != NULL);
114+
#ifdef Py_DEBUG
115+
_Py_EnsureTstateNotNULL(tstate);
116+
#endif
100117
return tstate->interp;
101118
}
102119

Lib/test/test_capi.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,10 @@ def test_no_FatalError_infinite_loop(self):
6868
self.assertTrue(err.rstrip().startswith(
6969
b'Fatal Python error: '
7070
b'PyThreadState_Get: '
71-
b'current thread state is NULL (released GIL?)'))
71+
b'the function must be called with the GIL held, '
72+
b'but the GIL is released '
73+
b'(the current Python thread state is NULL)'),
74+
err)
7275

7376
def test_memoryview_from_NULL_pointer(self):
7477
self.assertRaises(ValueError, _testcapi.make_memoryview_from_NULL_pointer)

Python/ceval.c

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -240,16 +240,15 @@ UNSIGNAL_ASYNC_EXC(PyInterpreterState *interp)
240240
#endif
241241
#include "ceval_gil.h"
242242

243-
static void
244-
ensure_tstate_not_null(const char *func, PyThreadState *tstate)
243+
void _Py_NO_RETURN
244+
_Py_FatalError_TstateNULL(const char *func)
245245
{
246-
if (tstate == NULL) {
247-
_Py_FatalErrorFunc(func,
248-
"current thread state is NULL (released GIL?)");
249-
}
246+
_Py_FatalErrorFunc(func,
247+
"the function must be called with the GIL held, "
248+
"but the GIL is released "
249+
"(the current Python thread state is NULL)");
250250
}
251251

252-
253252
#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
254253
int
255254
_PyEval_ThreadsInitialized(PyInterpreterState *interp)
@@ -374,7 +373,7 @@ PyEval_AcquireLock(void)
374373
{
375374
_PyRuntimeState *runtime = &_PyRuntime;
376375
PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime);
377-
ensure_tstate_not_null(__func__, tstate);
376+
_Py_EnsureTstateNotNULL(tstate);
378377

379378
take_gil(tstate);
380379
}
@@ -403,7 +402,7 @@ _PyEval_ReleaseLock(PyThreadState *tstate)
403402
void
404403
PyEval_AcquireThread(PyThreadState *tstate)
405404
{
406-
ensure_tstate_not_null(__func__, tstate);
405+
_Py_EnsureTstateNotNULL(tstate);
407406

408407
take_gil(tstate);
409408

@@ -442,7 +441,7 @@ void
442441
_PyEval_ReInitThreads(_PyRuntimeState *runtime)
443442
{
444443
PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime);
445-
ensure_tstate_not_null(__func__, tstate);
444+
_Py_EnsureTstateNotNULL(tstate);
446445

447446
#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
448447
struct _gil_runtime_state *gil = &tstate->interp->ceval.gil;
@@ -486,7 +485,7 @@ PyEval_SaveThread(void)
486485
#else
487486
PyThreadState *tstate = _PyThreadState_Swap(&runtime->gilstate, NULL);
488487
#endif
489-
ensure_tstate_not_null(__func__, tstate);
488+
_Py_EnsureTstateNotNULL(tstate);
490489

491490
struct _ceval_runtime_state *ceval = &runtime->ceval;
492491
struct _ceval_state *ceval2 = &tstate->interp->ceval;
@@ -502,7 +501,7 @@ PyEval_SaveThread(void)
502501
void
503502
PyEval_RestoreThread(PyThreadState *tstate)
504503
{
505-
ensure_tstate_not_null(__func__, tstate);
504+
_Py_EnsureTstateNotNULL(tstate);
506505

507506
take_gil(tstate);
508507

@@ -944,7 +943,7 @@ eval_frame_handle_pending(PyThreadState *tstate)
944943
PyObject* _Py_HOT_FUNCTION
945944
_PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
946945
{
947-
ensure_tstate_not_null(__func__, tstate);
946+
_Py_EnsureTstateNotNULL(tstate);
948947

949948
#ifdef DXPAIRS
950949
int lastopcode = 0;

Python/errors.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1426,7 +1426,7 @@ void
14261426
_PyErr_WriteUnraisableMsg(const char *err_msg_str, PyObject *obj)
14271427
{
14281428
PyThreadState *tstate = _PyThreadState_GET();
1429-
assert(tstate != NULL);
1429+
_Py_EnsureTstateNotNULL(tstate);
14301430

14311431
PyObject *err_msg = NULL;
14321432
PyObject *exc_type, *exc_value, *exc_tb;

Python/pystate.c

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,6 @@ extern "C" {
3939
_Py_atomic_store_relaxed(&(gilstate)->tstate_current, \
4040
(uintptr_t)(value))
4141

42-
static void
43-
ensure_tstate_not_null(const char *func, PyThreadState *tstate)
44-
{
45-
if (tstate == NULL) {
46-
_Py_FatalErrorFunc(func,
47-
"current thread state is NULL (released GIL?)");
48-
}
49-
}
50-
51-
5242
/* Forward declarations */
5343
static PyThreadState *_PyGILState_GetThisThreadState(struct _gilstate_runtime_state *gilstate);
5444
static void _PyThreadState_Delete(PyThreadState *tstate, int check_current);
@@ -431,7 +421,7 @@ PyInterpreterState *
431421
PyInterpreterState_Get(void)
432422
{
433423
PyThreadState *tstate = _PyThreadState_GET();
434-
ensure_tstate_not_null(__func__, tstate);
424+
_Py_EnsureTstateNotNULL(tstate);
435425
PyInterpreterState *interp = tstate->interp;
436426
if (interp == NULL) {
437427
Py_FatalError("no current interpreter");
@@ -846,7 +836,7 @@ static void
846836
tstate_delete_common(PyThreadState *tstate,
847837
struct _gilstate_runtime_state *gilstate)
848838
{
849-
ensure_tstate_not_null(__func__, tstate);
839+
_Py_EnsureTstateNotNULL(tstate);
850840
PyInterpreterState *interp = tstate->interp;
851841
if (interp == NULL) {
852842
Py_FatalError("NULL interpreter");
@@ -897,7 +887,7 @@ PyThreadState_Delete(PyThreadState *tstate)
897887
void
898888
_PyThreadState_DeleteCurrent(PyThreadState *tstate)
899889
{
900-
ensure_tstate_not_null(__func__, tstate);
890+
_Py_EnsureTstateNotNULL(tstate);
901891
struct _gilstate_runtime_state *gilstate = &tstate->interp->runtime->gilstate;
902892
tstate_delete_common(tstate, gilstate);
903893
_PyRuntimeGILState_SetThreadState(gilstate, NULL);
@@ -975,7 +965,7 @@ PyThreadState *
975965
PyThreadState_Get(void)
976966
{
977967
PyThreadState *tstate = _PyThreadState_GET();
978-
ensure_tstate_not_null(__func__, tstate);
968+
_Py_EnsureTstateNotNULL(tstate);
979969
return tstate;
980970
}
981971

Python/sysmodule.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,7 @@ static PyObject *
457457
sys_audit(PyObject *self, PyObject *const *args, Py_ssize_t argc)
458458
{
459459
PyThreadState *tstate = _PyThreadState_GET();
460-
assert(tstate != NULL);
460+
_Py_EnsureTstateNotNULL(tstate);
461461

462462
if (argc == 0) {
463463
_PyErr_SetString(tstate, PyExc_TypeError,

0 commit comments

Comments
 (0)