@@ -6343,38 +6343,23 @@ _PyEval_SetProfile(PyThreadState *tstate, Py_tracefunc func, PyObject *arg)
6343
6343
/* The caller must hold the GIL */
6344
6344
assert (PyGILState_Check ());
6345
6345
6346
- static int reentrant = 0 ;
6347
- if (reentrant ) {
6348
- _PyErr_SetString (tstate , PyExc_RuntimeError , "Cannot install a profile function "
6349
- "while another profile function is being installed" );
6350
- reentrant = 0 ;
6351
- return -1 ;
6352
- }
6353
- reentrant = 1 ;
6354
-
6355
6346
/* Call _PySys_Audit() in the context of the current thread state,
6356
6347
even if tstate is not the current thread state. */
6357
6348
PyThreadState * current_tstate = _PyThreadState_GET ();
6358
6349
if (_PySys_Audit (current_tstate , "sys.setprofile" , NULL ) < 0 ) {
6359
- reentrant = 0 ;
6360
6350
return -1 ;
6361
6351
}
6362
6352
6363
- PyObject * profileobj = tstate -> c_profileobj ;
6364
-
6365
- tstate -> c_profilefunc = NULL ;
6366
- tstate -> c_profileobj = NULL ;
6367
- /* Must make sure that tracing is not ignored if 'profileobj' is freed */
6368
- _PyThreadState_UpdateTracingState (tstate );
6369
- Py_XDECREF (profileobj );
6370
-
6371
- Py_XINCREF (arg );
6372
- tstate -> c_profileobj = arg ;
6373
6353
tstate -> c_profilefunc = func ;
6374
-
6354
+ PyObject * old_profileobj = tstate -> c_profileobj ;
6355
+ tstate -> c_profileobj = Py_XNewRef (arg );
6375
6356
/* Flag that tracing or profiling is turned on */
6376
6357
_PyThreadState_UpdateTracingState (tstate );
6377
- reentrant = 0 ;
6358
+
6359
+ // gh-98257: Only call Py_XDECREF() once the new profile function is fully
6360
+ // set, so it's safe to call sys.setprofile() again (reentrant call).
6361
+ Py_XDECREF (old_profileobj );
6362
+
6378
6363
return 0 ;
6379
6364
}
6380
6365
@@ -6416,39 +6401,23 @@ _PyEval_SetTrace(PyThreadState *tstate, Py_tracefunc func, PyObject *arg)
6416
6401
/* The caller must hold the GIL */
6417
6402
assert (PyGILState_Check ());
6418
6403
6419
- static int reentrant = 0 ;
6420
-
6421
- if (reentrant ) {
6422
- _PyErr_SetString (tstate , PyExc_RuntimeError , "Cannot install a trace function "
6423
- "while another trace function is being installed" );
6424
- reentrant = 0 ;
6425
- return -1 ;
6426
- }
6427
- reentrant = 1 ;
6428
-
6429
6404
/* Call _PySys_Audit() in the context of the current thread state,
6430
6405
even if tstate is not the current thread state. */
6431
6406
PyThreadState * current_tstate = _PyThreadState_GET ();
6432
6407
if (_PySys_Audit (current_tstate , "sys.settrace" , NULL ) < 0 ) {
6433
- reentrant = 0 ;
6434
6408
return -1 ;
6435
6409
}
6436
6410
6437
- PyObject * traceobj = tstate -> c_traceobj ;
6438
-
6439
- tstate -> c_tracefunc = NULL ;
6440
- tstate -> c_traceobj = NULL ;
6441
- /* Must make sure that profiling is not ignored if 'traceobj' is freed */
6442
- _PyThreadState_UpdateTracingState (tstate );
6443
- Py_XINCREF (arg );
6444
- Py_XDECREF (traceobj );
6445
- tstate -> c_traceobj = arg ;
6446
6411
tstate -> c_tracefunc = func ;
6447
-
6412
+ PyObject * old_traceobj = tstate -> c_traceobj ;
6413
+ tstate -> c_traceobj = Py_XNewRef (arg );
6448
6414
/* Flag that tracing or profiling is turned on */
6449
6415
_PyThreadState_UpdateTracingState (tstate );
6450
6416
6451
- reentrant = 0 ;
6417
+ // gh-98257: Only call Py_XDECREF() once the new trace function is fully
6418
+ // set, so it's safe to call sys.settrace() again (reentrant call).
6419
+ Py_XDECREF (old_traceobj );
6420
+
6452
6421
return 0 ;
6453
6422
}
6454
6423
0 commit comments