Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 596cd5c

Browse filesBrowse files
authored
gh-154431: Fix data race in sys.audithook (#154462)
1 parent f195b2e commit 596cd5c
Copy full SHA for 596cd5c

5 files changed

+35-8Lines changed: 35 additions & 8 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎Include/internal/pycore_interp_structs.h‎

Copy file name to clipboardExpand all lines: Include/internal/pycore_interp_structs.h
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -977,6 +977,7 @@ struct _is {
977977
struct _obmalloc_state *obmalloc;
978978

979979
PyObject *audit_hooks;
980+
PyMutex audit_hooks_mutex;
980981
PyType_WatchCallback type_watchers[TYPE_MAX_WATCHERS];
981982
PyCode_WatchCallback code_watchers[CODE_MAX_WATCHERS];
982983
PyContext_WatchCallback context_watchers[CONTEXT_MAX_WATCHERS];
Collapse file

‎Lib/test/test_free_threading/test_sys.py‎

Copy file name to clipboardExpand all lines: Lib/test/test_free_threading/test_sys.py
+14Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,20 @@ def worker(worker_id):
4444
workers = [lambda: worker(i) for i in range(5)]
4545
threading_helper.run_concurrently(workers)
4646

47+
def test_sys_audit_hooks(self):
48+
def _hook(*args):
49+
return None
50+
51+
def adder():
52+
for _ in range(100):
53+
sys.addaudithook(_hook)
54+
55+
def auditor():
56+
for _ in range(2000):
57+
sys.audit("fusil.tsan.test")
58+
59+
threading_helper.run_concurrently([adder, auditor])
60+
4761

4862
if __name__ == "__main__":
4963
unittest.main()
Collapse file
+1Lines changed: 1 addition & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixes a data race in free-threading build in :func:`sys.addaudithook`.
Collapse file

‎Python/pystate.c‎

Copy file name to clipboardExpand all lines: Python/pystate.c
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,7 @@ init_interpreter(PyInterpreterState *interp,
578578
llist_init(&interp->mem_free_queue.head);
579579
llist_init(&interp->asyncio_tasks_head);
580580
interp->asyncio_tasks_lock = (PyMutex){0};
581+
interp->audit_hooks_mutex = (PyMutex){0};
581582
for (int i = 0; i < _PY_MONITORING_UNGROUPED_EVENTS; i++) {
582583
interp->monitors.tools[i] = 0;
583584
}
Collapse file

‎Python/sysmodule.c‎

Copy file name to clipboardExpand all lines: Python/sysmodule.c
+18-8Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ should_audit(PyInterpreterState *interp)
236236
return 0;
237237
}
238238
return (interp->runtime->audit_hooks.head
239-
|| interp->audit_hooks
239+
|| FT_ATOMIC_LOAD_PTR_ACQUIRE(interp->audit_hooks)
240240
|| PyDTrace_AUDIT_ENABLED());
241241
}
242242

@@ -306,13 +306,14 @@ sys_audit_tstate(PyThreadState *ts, const char *event,
306306
}
307307

308308
/* Call interpreter hooks */
309-
if (is->audit_hooks) {
309+
PyObject *audit_hooks = FT_ATOMIC_LOAD_PTR_ACQUIRE(is->audit_hooks);
310+
if (audit_hooks) {
310311
eventName = PyUnicode_FromString(event);
311312
if (!eventName) {
312313
goto exit;
313314
}
314315

315-
hooks = PyObject_GetIter(is->audit_hooks);
316+
hooks = PyObject_GetIter(audit_hooks);
316317
if (!hooks) {
317318
goto exit;
318319
}
@@ -536,20 +537,29 @@ sys_addaudithook_impl(PyObject *module, PyObject *hook)
536537
}
537538

538539
PyInterpreterState *interp = tstate->interp;
540+
PyMutex mutex = interp->audit_hooks_mutex;
541+
PyMutex_Lock(&mutex);
542+
539543
if (interp->audit_hooks == NULL) {
540-
interp->audit_hooks = PyList_New(0);
541-
if (interp->audit_hooks == NULL) {
542-
return NULL;
544+
PyObject *new_list = PyList_New(0);
545+
if (new_list == NULL) {
546+
goto error;
543547
}
544548
/* Avoid having our list of hooks show up in the GC module */
545-
PyObject_GC_UnTrack(interp->audit_hooks);
549+
PyObject_GC_UnTrack(new_list);
550+
FT_ATOMIC_STORE_PTR_RELEASE(interp->audit_hooks, new_list);
546551
}
547552

548553
if (PyList_Append(interp->audit_hooks, hook) < 0) {
549-
return NULL;
554+
goto error;
550555
}
551556

557+
PyMutex_Unlock(&mutex);
552558
Py_RETURN_NONE;
559+
560+
error:
561+
PyMutex_Unlock(&mutex);
562+
return NULL;
553563
}
554564

555565
/*[clinic input]

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.