Skip to content

Commit 4d0a659

Browse files
gh-128360: Add _Py_AssertHoldsTstate as assertion for holding a thread state (#128361)
Co-authored-by: Kumar Aditya <[email protected]>
1 parent c6b570e commit 4d0a659

File tree

11 files changed

+48
-32
lines changed

11 files changed

+48
-32
lines changed

Include/internal/pycore_pystate.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,19 @@ PyAPI_FUNC(const PyConfig*) _Py_GetConfig(void);
300300
// See also PyInterpreterState_Get() and _PyInterpreterState_GET().
301301
extern PyInterpreterState* _PyGILState_GetInterpreterStateUnsafe(void);
302302

303+
#ifndef NDEBUG
304+
/* Modern equivalent of assert(PyGILState_Check()) */
305+
static inline void
306+
_Py_AssertHoldsTstateFunc(const char *func)
307+
{
308+
PyThreadState *tstate = _PyThreadState_GET();
309+
_Py_EnsureFuncTstateNotNULL(func, tstate);
310+
}
311+
#define _Py_AssertHoldsTstate() _Py_AssertHoldsTstateFunc(__func__)
312+
#else
313+
#define _Py_AssertHoldsTstate()
314+
#endif
315+
303316
#ifdef __cplusplus
304317
}
305318
#endif

Modules/socketmodule.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ Local naming conventions:
110110
#include "pycore_fileutils.h" // _Py_set_inheritable()
111111
#include "pycore_moduleobject.h" // _PyModule_GetState
112112
#include "pycore_time.h" // _PyTime_AsMilliseconds()
113+
#include "pycore_pystate.h" // _Py_AssertHoldsTstate()
113114
#include "pycore_pyatomic_ft_wrappers.h"
114115

115116
#ifdef _Py_MEMORY_SANITIZER
@@ -822,8 +823,8 @@ internal_select(PySocketSockObject *s, int writing, PyTime_t interval,
822823
struct timeval tv, *tvp;
823824
#endif
824825

825-
/* must be called with the GIL held */
826-
assert(PyGILState_Check());
826+
/* must be called with a thread state */
827+
_Py_AssertHoldsTstate();
827828

828829
/* Error condition is for output only */
829830
assert(!(connect && !writing));
@@ -936,8 +937,8 @@ sock_call_ex(PySocketSockObject *s,
936937
int deadline_initialized = 0;
937938
int res;
938939

939-
/* sock_call() must be called with the GIL held. */
940-
assert(PyGILState_Check());
940+
/* sock_call() must be called with a thread state. */
941+
_Py_AssertHoldsTstate();
941942

942943
/* outer loop to retry select() when select() is interrupted by a signal
943944
or to retry select()+sock_func() on false positive (see above) */

Objects/object.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3073,14 +3073,14 @@ _Py_SetRefcnt(PyObject *ob, Py_ssize_t refcnt)
30733073
}
30743074

30753075
int PyRefTracer_SetTracer(PyRefTracer tracer, void *data) {
3076-
assert(PyGILState_Check());
3076+
_Py_AssertHoldsTstate();
30773077
_PyRuntime.ref_tracer.tracer_func = tracer;
30783078
_PyRuntime.ref_tracer.tracer_data = data;
30793079
return 0;
30803080
}
30813081

30823082
PyRefTracer PyRefTracer_GetTracer(void** data) {
3083-
assert(PyGILState_Check());
3083+
_Py_AssertHoldsTstate();
30843084
if (data != NULL) {
30853085
*data = _PyRuntime.ref_tracer.tracer_data;
30863086
}

Objects/obmalloc.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2909,7 +2909,8 @@ _PyMem_DebugRawRealloc(void *ctx, void *p, size_t nbytes)
29092909
static inline void
29102910
_PyMem_DebugCheckGIL(const char *func)
29112911
{
2912-
if (!PyGILState_Check()) {
2912+
PyThreadState *tstate = _PyThreadState_GET();
2913+
if (tstate == NULL) {
29132914
#ifndef Py_GIL_DISABLED
29142915
_Py_FatalErrorFunc(func,
29152916
"Python memory allocator called "

Python/ceval_gil.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -995,7 +995,7 @@ _Py_unset_eval_breaker_bit_all(PyInterpreterState *interp, uintptr_t bit)
995995
void
996996
_Py_FinishPendingCalls(PyThreadState *tstate)
997997
{
998-
assert(PyGILState_Check());
998+
_Py_AssertHoldsTstate();
999999
assert(_PyThreadState_CheckConsistency(tstate));
10001000

10011001
struct _pending_calls *pending = &tstate->interp->ceval.pending;
@@ -1056,7 +1056,7 @@ _PyEval_MakePendingCalls(PyThreadState *tstate)
10561056
int
10571057
Py_MakePendingCalls(void)
10581058
{
1059-
assert(PyGILState_Check());
1059+
_Py_AssertHoldsTstate();
10601060

10611061
PyThreadState *tstate = _PyThreadState_GET();
10621062
assert(_PyThreadState_CheckConsistency(tstate));

Python/errors.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -314,8 +314,8 @@ _PyErr_SetLocaleString(PyObject *exception, const char *string)
314314
PyObject* _Py_HOT_FUNCTION
315315
PyErr_Occurred(void)
316316
{
317-
/* The caller must hold the GIL. */
318-
assert(PyGILState_Check());
317+
/* The caller must hold a thread state. */
318+
_Py_AssertHoldsTstate();
319319

320320
PyThreadState *tstate = _PyThreadState_GET();
321321
return _PyErr_Occurred(tstate);

Python/fileutils.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "Python.h"
22
#include "pycore_fileutils.h" // fileutils definitions
33
#include "pycore_runtime.h" // _PyRuntime
4+
#include "pycore_pystate.h" // _Py_AssertHoldsTstate()
45
#include "osdefs.h" // SEP
56

67
#include <stdlib.h> // mbstowcs()
@@ -1311,7 +1312,7 @@ _Py_fstat(int fd, struct _Py_stat_struct *status)
13111312
{
13121313
int res;
13131314

1314-
assert(PyGILState_Check());
1315+
_Py_AssertHoldsTstate();
13151316

13161317
Py_BEGIN_ALLOW_THREADS
13171318
res = _Py_fstat_noraise(fd, status);
@@ -1691,7 +1692,7 @@ int
16911692
_Py_open(const char *pathname, int flags)
16921693
{
16931694
/* _Py_open() must be called with the GIL held. */
1694-
assert(PyGILState_Check());
1695+
_Py_AssertHoldsTstate();
16951696
return _Py_open_impl(pathname, flags, 1);
16961697
}
16971698

@@ -1766,7 +1767,7 @@ _Py_wfopen(const wchar_t *path, const wchar_t *mode)
17661767
FILE*
17671768
Py_fopen(PyObject *path, const char *mode)
17681769
{
1769-
assert(PyGILState_Check());
1770+
_Py_AssertHoldsTstate();
17701771

17711772
if (PySys_Audit("open", "Osi", path, mode, 0) < 0) {
17721773
return NULL;
@@ -1881,7 +1882,7 @@ _Py_read(int fd, void *buf, size_t count)
18811882
int err;
18821883
int async_err = 0;
18831884

1884-
assert(PyGILState_Check());
1885+
_Py_AssertHoldsTstate();
18851886

18861887
/* _Py_read() must not be called with an exception set, otherwise the
18871888
* caller may think that read() was interrupted by a signal and the signal
@@ -2047,7 +2048,7 @@ _Py_write_impl(int fd, const void *buf, size_t count, int gil_held)
20472048
Py_ssize_t
20482049
_Py_write(int fd, const void *buf, size_t count)
20492050
{
2050-
assert(PyGILState_Check());
2051+
_Py_AssertHoldsTstate();
20512052

20522053
/* _Py_write() must not be called with an exception set, otherwise the
20532054
* caller may think that write() was interrupted by a signal and the signal
@@ -2675,7 +2676,7 @@ _Py_dup(int fd)
26752676
HANDLE handle;
26762677
#endif
26772678

2678-
assert(PyGILState_Check());
2679+
_Py_AssertHoldsTstate();
26792680

26802681
#ifdef MS_WINDOWS
26812682
handle = _Py_get_osfhandle(fd);

Python/legacy_tracing.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -491,8 +491,8 @@ int
491491
_PyEval_SetProfile(PyThreadState *tstate, Py_tracefunc func, PyObject *arg)
492492
{
493493
assert(is_tstate_valid(tstate));
494-
/* The caller must hold the GIL */
495-
assert(PyGILState_Check());
494+
/* The caller must hold a thread state */
495+
_Py_AssertHoldsTstate();
496496

497497
/* Call _PySys_Audit() in the context of the current thread state,
498498
even if tstate is not the current thread state. */
@@ -586,8 +586,8 @@ int
586586
_PyEval_SetTrace(PyThreadState *tstate, Py_tracefunc func, PyObject *arg)
587587
{
588588
assert(is_tstate_valid(tstate));
589-
/* The caller must hold the GIL */
590-
assert(PyGILState_Check());
589+
/* The caller must hold a thread state */
590+
_Py_AssertHoldsTstate();
591591

592592
/* Call _PySys_Audit() in the context of the current thread state,
593593
even if tstate is not the current thread state. */

Python/pystate.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2897,7 +2897,6 @@ _PyInterpreterState_GetConfigCopy(PyConfig *config)
28972897
const PyConfig*
28982898
_Py_GetConfig(void)
28992899
{
2900-
assert(PyGILState_Check());
29012900
PyThreadState *tstate = current_fast_get();
29022901
_Py_EnsureTstateNotNULL(tstate);
29032902
return _PyInterpreterState_GetConfig(tstate->interp);

Python/pytime.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "Python.h"
22
#include "pycore_time.h" // PyTime_t
3+
#include "pycore_pystate.h" // _Py_AssertHoldsTstate()
34

45
#include <time.h> // gmtime_r()
56
#ifdef HAVE_SYS_TIME_H
@@ -897,14 +898,14 @@ _PyTime_AsTimespec(PyTime_t t, struct timespec *ts)
897898
#endif
898899

899900

900-
// N.B. If raise_exc=0, this may be called without the GIL.
901+
// N.B. If raise_exc=0, this may be called without a thread state.
901902
static int
902903
py_get_system_clock(PyTime_t *tp, _Py_clock_info_t *info, int raise_exc)
903904
{
904905
assert(info == NULL || raise_exc);
905906
if (raise_exc) {
906-
// raise_exc requires to hold the GIL
907-
assert(PyGILState_Check());
907+
// raise_exc requires to hold a thread state
908+
_Py_AssertHoldsTstate();
908909
}
909910

910911
#ifdef MS_WINDOWS
@@ -1142,14 +1143,14 @@ py_mach_timebase_info(_PyTimeFraction *base, int raise_exc)
11421143
#endif
11431144

11441145

1145-
// N.B. If raise_exc=0, this may be called without the GIL.
1146+
// N.B. If raise_exc=0, this may be called without a thread state.
11461147
static int
11471148
py_get_monotonic_clock(PyTime_t *tp, _Py_clock_info_t *info, int raise_exc)
11481149
{
11491150
assert(info == NULL || raise_exc);
11501151
if (raise_exc) {
1151-
// raise_exc requires to hold the GIL
1152-
assert(PyGILState_Check());
1152+
// raise_exc requires to hold a thread state
1153+
_Py_AssertHoldsTstate();
11531154
}
11541155

11551156
#if defined(MS_WINDOWS)

Python/tracemalloc.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@ traceback_new(void)
367367
traceback_t *traceback;
368368
_Py_hashtable_entry_t *entry;
369369

370-
assert(PyGILState_Check());
370+
_Py_AssertHoldsTstate();
371371

372372
/* get frames */
373373
traceback = tracemalloc_traceback;
@@ -749,7 +749,7 @@ static void
749749
tracemalloc_clear_traces_unlocked(void)
750750
{
751751
// Clearing tracemalloc_filenames requires the GIL to call Py_DECREF()
752-
assert(PyGILState_Check());
752+
_Py_AssertHoldsTstate();
753753

754754
set_reentrant(1);
755755

@@ -1302,7 +1302,7 @@ PyTraceMalloc_Untrack(unsigned int domain, uintptr_t ptr)
13021302
void
13031303
_PyTraceMalloc_Fini(void)
13041304
{
1305-
assert(PyGILState_Check());
1305+
_Py_AssertHoldsTstate();
13061306
tracemalloc_deinit();
13071307
}
13081308

@@ -1323,7 +1323,7 @@ _PyTraceMalloc_TraceRef(PyObject *op, PyRefTracerEvent event,
13231323
return 0;
13241324
}
13251325

1326-
assert(PyGILState_Check());
1326+
_Py_AssertHoldsTstate();
13271327
TABLES_LOCK();
13281328

13291329
if (!tracemalloc_config.tracing) {

0 commit comments

Comments
 (0)