]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-136870: fix data races in instrumentation of bytecode (#136994)
authorKumar Aditya <kumaraditya@python.org>
Thu, 24 Jul 2025 17:58:46 +0000 (23:28 +0530)
committerGitHub <noreply@github.com>
Thu, 24 Jul 2025 17:58:46 +0000 (17:58 +0000)
De-instrumenting code objects modifies the thread local bytecode for all threads as such, holding the critical section on the code object is not sufficient and leads to data races. Now, the de-instrumentation is now performed under a stop the world pause as such no thread races with executing the thread local bytecode while it is being de-instrumented.

Misc/NEWS.d/next/Core_and_Builtins/2025-07-24-17-30-58.gh-issue-136870.ncx82J.rst [new file with mode: 0644]
Python/instrumentation.c

diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-24-17-30-58.gh-issue-136870.ncx82J.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-24-17-30-58.gh-issue-136870.ncx82J.rst
new file mode 100644 (file)
index 0000000..7552dc6
--- /dev/null
@@ -0,0 +1 @@
+Fix data races while de-instrumenting bytecode of code objects running concurrently in threads.
index 44de480cd2304a45d9e1fac3c1df33ea1a854936..f9913cff402ed1f6e85faec4bdca49414643c046 100644 (file)
@@ -1190,9 +1190,10 @@ call_instrumentation_vector(
                 break;
             }
             else {
-                LOCK_CODE(code);
+                PyInterpreterState *interp = tstate->interp;
+                _PyEval_StopTheWorld(interp);
                 remove_tools(code, offset, event, 1 << tool);
-                UNLOCK_CODE();
+                _PyEval_StartTheWorld(interp);
             }
         }
     }
@@ -1381,9 +1382,10 @@ _Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame,
         }
         else {
             /* DISABLE  */
-            LOCK_CODE(code);
+            PyInterpreterState *interp = tstate->interp;
+            _PyEval_StopTheWorld(interp);
             remove_line_tools(code, i, 1 << tool);
-            UNLOCK_CODE();
+            _PyEval_StartTheWorld(interp);
         }
     } while (tools);
     Py_DECREF(line_obj);
@@ -1438,9 +1440,10 @@ _Py_call_instrumentation_instruction(PyThreadState *tstate, _PyInterpreterFrame*
         }
         else {
             /* DISABLE  */
-            LOCK_CODE(code);
+            PyInterpreterState *interp = tstate->interp;
+            _PyEval_StopTheWorld(interp);
             remove_per_instruction_tools(code, offset, 1 << tool);
-            UNLOCK_CODE();
+            _PyEval_StartTheWorld(interp);
         }
     }
     Py_DECREF(offset_obj);
@@ -2995,9 +2998,10 @@ branch_handler_vectorcall(
             // Orphaned NOT_TAKEN -- Jump removed by the compiler
             return res;
         }
-        LOCK_CODE(code);
+        PyInterpreterState *interp = _PyInterpreterState_GET();
+        _PyEval_StopTheWorld(interp);
         remove_tools(code, offset, other_event, 1 << self->tool_id);
-        UNLOCK_CODE();
+        _PyEval_StartTheWorld(interp);
     }
     return res;
 }