summaryrefslogtreecommitdiffstats
path: root/Python/sysmodule.c
diff options
context:
space:
mode:
authorEric Snow <ericsnowcurrently@gmail.com>2023-06-08 18:38:15 (GMT)
committerGitHub <noreply@github.com>2023-06-08 18:38:15 (GMT)
commite822a676f1f3bef6c5413e9b856db481c08ac2a5 (patch)
tree5495fed901962b43f4a68a57ace3317b0067d29e /Python/sysmodule.c
parent34c63b86d3c33a85acf55a0c5c118304754e145d (diff)
downloadcpython-e822a676f1f3bef6c5413e9b856db481c08ac2a5.zip
cpython-e822a676f1f3bef6c5413e9b856db481c08ac2a5.tar.gz
cpython-e822a676f1f3bef6c5413e9b856db481c08ac2a5.tar.bz2
gh-100227: Lock Around Adding Global Audit Hooks (gh-105515)
The risk of a race with this state is relatively low, but we play it safe anyway.
Diffstat (limited to 'Python/sysmodule.c')
-rw-r--r--Python/sysmodule.c56
1 files changed, 39 insertions, 17 deletions
diff --git a/Python/sysmodule.c b/Python/sysmodule.c
index 4427e73..7027410 100644
--- a/Python/sysmodule.c
+++ b/Python/sysmodule.c
@@ -168,7 +168,7 @@ should_audit(PyInterpreterState *interp)
if (!interp) {
return 0;
}
- return (interp->runtime->audit_hook_head
+ return (interp->runtime->audit_hooks.head
|| interp->audit_hooks
|| PyDTrace_AUDIT_ENABLED());
}
@@ -224,8 +224,11 @@ sys_audit_tstate(PyThreadState *ts, const char *event,
goto exit;
}
- /* Call global hooks */
- _Py_AuditHookEntry *e = is->runtime->audit_hook_head;
+ /* Call global hooks
+ *
+ * We don't worry about any races on hooks getting added,
+ * since that would not leave is in an inconsistent state. */
+ _Py_AuditHookEntry *e = is->runtime->audit_hooks.head;
for (; e; e = e->next) {
if (e->hookCFunction(event, eventArgs, e->userData) < 0) {
goto exit;
@@ -353,8 +356,12 @@ _PySys_ClearAuditHooks(PyThreadState *ts)
_PySys_Audit(ts, "cpython._PySys_ClearAuditHooks", NULL);
_PyErr_Clear(ts);
- _Py_AuditHookEntry *e = runtime->audit_hook_head, *n;
- runtime->audit_hook_head = NULL;
+ /* We don't worry about the very unlikely race right here,
+ * since it's entirely benign. Nothing else removes entries
+ * from the list and adding an entry right now would not cause
+ * any trouble. */
+ _Py_AuditHookEntry *e = runtime->audit_hooks.head, *n;
+ runtime->audit_hooks.head = NULL;
while (e) {
n = e->next;
PyMem_RawFree(e);
@@ -362,6 +369,22 @@ _PySys_ClearAuditHooks(PyThreadState *ts)
}
}
+static void
+add_audit_hook_entry_unlocked(_PyRuntimeState *runtime,
+ _Py_AuditHookEntry *entry)
+{
+ if (runtime->audit_hooks.head == NULL) {
+ runtime->audit_hooks.head = entry;
+ }
+ else {
+ _Py_AuditHookEntry *last = runtime->audit_hooks.head;
+ while (last->next) {
+ last = last->next;
+ }
+ last->next = entry;
+ }
+}
+
int
PySys_AddAuditHook(Py_AuditHookFunction hook, void *userData)
{
@@ -389,29 +412,28 @@ PySys_AddAuditHook(Py_AuditHookFunction hook, void *userData)
}
}
- _Py_AuditHookEntry *e = runtime->audit_hook_head;
- if (!e) {
- e = (_Py_AuditHookEntry*)PyMem_RawMalloc(sizeof(_Py_AuditHookEntry));
- runtime->audit_hook_head = e;
- } else {
- while (e->next) {
- e = e->next;
- }
- e = e->next = (_Py_AuditHookEntry*)PyMem_RawMalloc(
+ _Py_AuditHookEntry *e = (_Py_AuditHookEntry*)PyMem_RawMalloc(
sizeof(_Py_AuditHookEntry));
- }
-
if (!e) {
if (tstate != NULL) {
_PyErr_NoMemory(tstate);
}
return -1;
}
-
e->next = NULL;
e->hookCFunction = (Py_AuditHookFunction)hook;
e->userData = userData;
+ if (runtime->audit_hooks.mutex == NULL) {
+ /* The runtime must not be initailized yet. */
+ add_audit_hook_entry_unlocked(runtime, e);
+ }
+ else {
+ PyThread_acquire_lock(runtime->audit_hooks.mutex, WAIT_LOCK);
+ add_audit_hook_entry_unlocked(runtime, e);
+ PyThread_release_lock(runtime->audit_hooks.mutex);
+ }
+
return 0;
}