| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 9dd28d2 commit b55cf2c
5 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -61,6 +61,10 @@ _Py_ThreadCanHandlePendingCalls(void) | |||
| 61 | 61 | } | |
| 62 | 62 | ||
| 63 | 63 | ||
| 64 | + #ifndef NDEBUG | ||
| 65 | + extern int _PyThreadState_CheckConsistency(PyThreadState *tstate); | ||
| 66 | + #endif | ||
| 67 | + | ||
| 64 | 68 | /* Variable and macro for in-line access to current thread | |
| 65 | 69 | and interpreter state */ | |
| 66 | 70 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1076,9 +1076,12 @@ static void | |||
| 1076 | 1076 | thread_run(void *boot_raw) | |
| 1077 | 1077 | { | |
| 1078 | 1078 | struct bootstate *boot = (struct bootstate *) boot_raw; | |
| 1079 | - PyThreadState *tstate; | ||
| 1079 | + PyThreadState *tstate = boot->tstate; | ||
| 1080 | + | ||
| 1081 | + // gh-104690: If Python is being finalized and PyInterpreterState_Delete() | ||
| 1082 | + // was called, tstate becomes a dangling pointer. | ||
| 1083 | + assert(_PyThreadState_CheckConsistency(tstate)); | ||
| 1080 | 1084 | ||
| 1081 | - tstate = boot->tstate; | ||
| 1082 | 1085 | tstate->thread_id = PyThread_get_thread_ident(); | |
| 1083 | 1086 | #ifdef PY_HAVE_THREAD_NATIVE_ID | |
| 1084 | 1087 | tstate->native_thread_id = PyThread_get_thread_native_id(); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -216,20 +216,6 @@ _PyEvalFrameClearAndPop(PyThreadState *tstate, _PyInterpreterFrame *frame); | |||
| 216 | 216 | "cannot access free variable '%s' where it is not associated with a" \ | |
| 217 | 217 | " value in enclosing scope" | |
| 218 | 218 | ||
| 219 | - #ifndef NDEBUG | ||
| 220 | - /* Ensure that tstate is valid: sanity check for PyEval_AcquireThread() and | ||
| 221 | - PyEval_RestoreThread(). Detect if tstate memory was freed. It can happen | ||
| 222 | - when a thread continues to run after Python finalization, especially | ||
| 223 | - daemon threads. */ | ||
| 224 | - static int | ||
| 225 | - is_tstate_valid(PyThreadState *tstate) | ||
| 226 | - { | ||
| 227 | - assert(!_PyMem_IsPtrFreed(tstate)); | ||
| 228 | - assert(!_PyMem_IsPtrFreed(tstate->interp)); | ||
| 229 | - return 1; | ||
| 230 | - } | ||
| 231 | - #endif | ||
| 232 | - | ||
| 233 | 219 | ||
| 234 | 220 | /* This can set eval_breaker to 0 even though gil_drop_request became | |
| 235 | 221 | 1. We believe this is all right because the eval loop will release | |
@@ -464,7 +450,7 @@ PyEval_AcquireThread(PyThreadState *tstate) | |||
| 464 | 450 | void | |
| 465 | 451 | PyEval_ReleaseThread(PyThreadState *tstate) | |
| 466 | 452 | { | |
| 467 | - assert(is_tstate_valid(tstate)); | ||
| 453 | + assert(_PyThreadState_CheckConsistency(tstate)); | ||
| 468 | 454 | ||
| 469 | 455 | _PyRuntimeState *runtime = tstate->interp->runtime; | |
| 470 | 456 | PyThreadState *new_tstate = _PyThreadState_Swap(&runtime->gilstate, NULL); | |
@@ -671,7 +657,7 @@ Py_AddPendingCall(int (*func)(void *), void *arg) | |||
| 671 | 657 | static int | |
| 672 | 658 | handle_signals(PyThreadState *tstate) | |
| 673 | 659 | { | |
| 674 | - assert(is_tstate_valid(tstate)); | ||
| 660 | + assert(_PyThreadState_CheckConsistency(tstate)); | ||
| 675 | 661 | if (!_Py_ThreadCanHandleSignals(tstate->interp)) { | |
| 676 | 662 | return 0; | |
| 677 | 663 | } | |
@@ -739,7 +725,7 @@ void | |||
| 739 | 725 | _Py_FinishPendingCalls(PyThreadState *tstate) | |
| 740 | 726 | { | |
| 741 | 727 | assert(PyGILState_Check()); | |
| 742 | - assert(is_tstate_valid(tstate)); | ||
| 728 | + assert(_PyThreadState_CheckConsistency(tstate)); | ||
| 743 | 729 | ||
| 744 | 730 | struct _pending_calls *pending = &tstate->interp->ceval.pending; | |
| 745 | 731 | ||
@@ -764,7 +750,7 @@ Py_MakePendingCalls(void) | |||
| 764 | 750 | assert(PyGILState_Check()); | |
| 765 | 751 | ||
| 766 | 752 | PyThreadState *tstate = _PyThreadState_GET(); | |
| 767 | - assert(is_tstate_valid(tstate)); | ||
| 753 | + assert(_PyThreadState_CheckConsistency(tstate)); | ||
| 768 | 754 | ||
| 769 | 755 | /* Python signal handler doesn't really queue a callback: it only signals | |
| 770 | 756 | that a signal was received, see _PyEval_SignalReceived(). */ | |
@@ -6947,7 +6933,7 @@ maybe_call_line_trace(Py_tracefunc func, PyObject *obj, | |||
| 6947 | 6933 | int | |
| 6948 | 6934 | _PyEval_SetProfile(PyThreadState *tstate, Py_tracefunc func, PyObject *arg) | |
| 6949 | 6935 | { | |
| 6950 | - assert(is_tstate_valid(tstate)); | ||
| 6936 | + assert(_PyThreadState_CheckConsistency(tstate)); | ||
| 6951 | 6937 | /* The caller must hold the GIL */ | |
| 6952 | 6938 | assert(PyGILState_Check()); | |
| 6953 | 6939 | ||
@@ -6999,7 +6985,7 @@ PyEval_SetProfile(Py_tracefunc func, PyObject *arg) | |||
| 6999 | 6985 | int | |
| 7000 | 6986 | _PyEval_SetTrace(PyThreadState *tstate, Py_tracefunc func, PyObject *arg) | |
| 7001 | 6987 | { | |
| 7002 | - assert(is_tstate_valid(tstate)); | ||
| 6988 | + assert(_PyThreadState_CheckConsistency(tstate)); | ||
| 7003 | 6989 | /* The caller must hold the GIL */ | |
| 7004 | 6990 | assert(PyGILState_Check()); | |
| 7005 | 6991 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -171,7 +171,7 @@ drop_gil(struct _ceval_runtime_state *ceval, struct _ceval_state *ceval2, | |||
| 171 | 171 | /* Not switched yet => wait */ | |
| 172 | 172 | if (((PyThreadState*)_Py_atomic_load_relaxed(&gil->last_holder)) == tstate) | |
| 173 | 173 | { | |
| 174 | - assert(is_tstate_valid(tstate)); | ||
| 174 | + assert(_PyThreadState_CheckConsistency(tstate)); | ||
| 175 | 175 | RESET_GIL_DROP_REQUEST(tstate->interp); | |
| 176 | 176 | /* NOTE: if COND_WAIT does not atomically start waiting when | |
| 177 | 177 | releasing the mutex, another thread can run through, take | |
@@ -226,7 +226,7 @@ take_gil(PyThreadState *tstate) | |||
| 226 | 226 | PyThread_exit_thread(); | |
| 227 | 227 | } | |
| 228 | 228 | ||
| 229 | - assert(is_tstate_valid(tstate)); | ||
| 229 | + assert(_PyThreadState_CheckConsistency(tstate)); | ||
| 230 | 230 | PyInterpreterState *interp = tstate->interp; | |
| 231 | 231 | struct _ceval_runtime_state *ceval = &interp->runtime->ceval; | |
| 232 | 232 | struct _ceval_state *ceval2 = &interp->ceval; | |
@@ -268,7 +268,7 @@ take_gil(PyThreadState *tstate) | |||
| 268 | 268 | } | |
| 269 | 269 | PyThread_exit_thread(); | |
| 270 | 270 | } | |
| 271 | - assert(is_tstate_valid(tstate)); | ||
| 271 | + assert(_PyThreadState_CheckConsistency(tstate)); | ||
| 272 | 272 | ||
| 273 | 273 | SET_GIL_DROP_REQUEST(interp); | |
| 274 | 274 | drop_requested = 1; | |
@@ -307,7 +307,7 @@ take_gil(PyThreadState *tstate) | |||
| 307 | 307 | drop_gil(ceval, ceval2, tstate); | |
| 308 | 308 | PyThread_exit_thread(); | |
| 309 | 309 | } | |
| 310 | - assert(is_tstate_valid(tstate)); | ||
| 310 | + assert(_PyThreadState_CheckConsistency(tstate)); | ||
| 311 | 311 | ||
| 312 | 312 | if (_Py_atomic_load_relaxed(&ceval2->gil_drop_request)) { | |
| 313 | 313 | RESET_GIL_DROP_REQUEST(interp); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2237,6 +2237,24 @@ _PyThreadState_PopFrame(PyThreadState *tstate, _PyInterpreterFrame * frame) | |||
| 2237 | 2237 | } | |
| 2238 | 2238 | ||
| 2239 | 2239 | ||
| 2240 | + #ifndef NDEBUG | ||
| 2241 | + // Check that a Python thread state valid. In practice, this function is used | ||
| 2242 | + // on a Python debug build to check if 'tstate' is a dangling pointer, if the | ||
| 2243 | + // PyThreadState memory has been freed. | ||
| 2244 | + // | ||
| 2245 | + // Usage: | ||
| 2246 | + // | ||
| 2247 | + // assert(_PyThreadState_CheckConsistency(tstate)); | ||
| 2248 | + int | ||
| 2249 | + _PyThreadState_CheckConsistency(PyThreadState *tstate) | ||
| 2250 | + { | ||
| 2251 | + assert(!_PyMem_IsPtrFreed(tstate)); | ||
| 2252 | + assert(!_PyMem_IsPtrFreed(tstate->interp)); | ||
| 2253 | + return 1; | ||
| 2254 | + } | ||
| 2255 | + #endif | ||
| 2256 | + | ||
| 2257 | + | ||
| 2240 | 2258 | #ifdef __cplusplus | |
| 2241 | 2259 | } | |
| 2242 | 2260 | #endif | |
| Back | FazBrowse Home | New Git URL |
0 commit comments