diff options
author | Eric Snow <ericsnowcurrently@gmail.com> | 2023-06-08 21:05:47 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-06-08 21:05:47 (GMT) |
commit | b08ea9a561e93e421e55b6eba5da350e6919708e (patch) | |
tree | b397169c3d13eb9554750ee3d747a1d9a826d5be /Python | |
parent | 2ad2bd8b14505ee92600e7988379cfac63086dab (diff) | |
download | cpython-b08ea9a561e93e421e55b6eba5da350e6919708e.zip cpython-b08ea9a561e93e421e55b6eba5da350e6919708e.tar.gz cpython-b08ea9a561e93e421e55b6eba5da350e6919708e.tar.bz2 |
[3.12] gh-100227: Lock Around Adding Global Audit Hooks (gh-105515) (gh-105525)
The risk of a race with this state is relatively low, but we play it safe anyway.
(cherry picked from commit e822a676f1f3bef6c5413e9b856db481c08ac2a5)
Diffstat (limited to 'Python')
-rw-r--r-- | Python/pystate.c | 7 | ||||
-rw-r--r-- | Python/sysmodule.c | 56 |
2 files changed, 43 insertions, 20 deletions
diff --git a/Python/pystate.c b/Python/pystate.c index e3a010a..14ae165 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -380,7 +380,7 @@ _Py_COMP_DIAG_IGNORE_DEPR_DECLS static const _PyRuntimeState initial = _PyRuntimeState_INIT(_PyRuntime); _Py_COMP_DIAG_POP -#define NUMLOCKS 6 +#define NUMLOCKS 7 #define LOCKS_INIT(runtime) \ { \ &(runtime)->interpreters.mutex, \ @@ -389,6 +389,7 @@ _Py_COMP_DIAG_POP &(runtime)->unicode_state.ids.lock, \ &(runtime)->imports.extensions.mutex, \ &(runtime)->atexit.mutex, \ + &(runtime)->audit_hooks.mutex, \ } static int @@ -432,7 +433,7 @@ init_runtime(_PyRuntimeState *runtime, runtime->open_code_hook = open_code_hook; runtime->open_code_userdata = open_code_userdata; - runtime->audit_hook_head = audit_hook_head; + runtime->audit_hooks.head = audit_hook_head; PyPreConfig_InitPythonConfig(&runtime->preconfig); @@ -458,7 +459,7 @@ _PyRuntimeState_Init(_PyRuntimeState *runtime) initialization and interpreter initialization. */ void *open_code_hook = runtime->open_code_hook; void *open_code_userdata = runtime->open_code_userdata; - _Py_AuditHookEntry *audit_hook_head = runtime->audit_hook_head; + _Py_AuditHookEntry *audit_hook_head = runtime->audit_hooks.head; // bpo-42882: Preserve next_index value if Py_Initialize()/Py_Finalize() // is called multiple times. Py_ssize_t unicode_next_index = runtime->unicode_state.ids.next_index; diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 33147f0..e6731e7 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; } |