@@ -168,7 +168,7 @@ should_audit(PyInterpreterState *interp)
168168 if (!interp ) {
169169 return 0 ;
170170 }
171- return (interp -> runtime -> audit_hook_head
171+ return (interp -> runtime -> audit_hooks . head
172172 || interp -> audit_hooks
173173 || PyDTrace_AUDIT_ENABLED ());
174174}
@@ -224,8 +224,11 @@ sys_audit_tstate(PyThreadState *ts, const char *event,
224224 goto exit ;
225225 }
226226
227- /* Call global hooks */
228- _Py_AuditHookEntry * e = is -> runtime -> audit_hook_head ;
227+ /* Call global hooks
228+ *
229+ * We don't worry about any races on hooks getting added,
230+ * since that would not leave is in an inconsistent state. */
231+ _Py_AuditHookEntry * e = is -> runtime -> audit_hooks .head ;
229232 for (; e ; e = e -> next ) {
230233 if (e -> hookCFunction (event , eventArgs , e -> userData ) < 0 ) {
231234 goto exit ;
@@ -353,15 +356,35 @@ _PySys_ClearAuditHooks(PyThreadState *ts)
353356 _PySys_Audit (ts , "cpython._PySys_ClearAuditHooks" , NULL );
354357 _PyErr_Clear (ts );
355358
356- _Py_AuditHookEntry * e = runtime -> audit_hook_head , * n ;
357- runtime -> audit_hook_head = NULL ;
359+ /* We don't worry about the very unlikely race right here,
360+ * since it's entirely benign. Nothing else removes entries
361+ * from the list and adding an entry right now would not cause
362+ * any trouble. */
363+ _Py_AuditHookEntry * e = runtime -> audit_hooks .head , * n ;
364+ runtime -> audit_hooks .head = NULL ;
358365 while (e ) {
359366 n = e -> next ;
360367 PyMem_RawFree (e );
361368 e = n ;
362369 }
363370}
364371
372+ static void
373+ add_audit_hook_entry_unlocked (_PyRuntimeState * runtime ,
374+ _Py_AuditHookEntry * entry )
375+ {
376+ if (runtime -> audit_hooks .head == NULL ) {
377+ runtime -> audit_hooks .head = entry ;
378+ }
379+ else {
380+ _Py_AuditHookEntry * last = runtime -> audit_hooks .head ;
381+ while (last -> next ) {
382+ last = last -> next ;
383+ }
384+ last -> next = entry ;
385+ }
386+ }
387+
365388int
366389PySys_AddAuditHook (Py_AuditHookFunction hook , void * userData )
367390{
@@ -389,29 +412,28 @@ PySys_AddAuditHook(Py_AuditHookFunction hook, void *userData)
389412 }
390413 }
391414
392- _Py_AuditHookEntry * e = runtime -> audit_hook_head ;
393- if (!e ) {
394- e = (_Py_AuditHookEntry * )PyMem_RawMalloc (sizeof (_Py_AuditHookEntry ));
395- runtime -> audit_hook_head = e ;
396- } else {
397- while (e -> next ) {
398- e = e -> next ;
399- }
400- e = e -> next = (_Py_AuditHookEntry * )PyMem_RawMalloc (
415+ _Py_AuditHookEntry * e = (_Py_AuditHookEntry * )PyMem_RawMalloc (
401416 sizeof (_Py_AuditHookEntry ));
402- }
403-
404417 if (!e ) {
405418 if (tstate != NULL ) {
406419 _PyErr_NoMemory (tstate );
407420 }
408421 return -1 ;
409422 }
410-
411423 e -> next = NULL ;
412424 e -> hookCFunction = (Py_AuditHookFunction )hook ;
413425 e -> userData = userData ;
414426
427+ if (runtime -> audit_hooks .mutex == NULL ) {
428+ /* The runtime must not be initailized yet. */
429+ add_audit_hook_entry_unlocked (runtime , e );
430+ }
431+ else {
432+ PyThread_acquire_lock (runtime -> audit_hooks .mutex , WAIT_LOCK );
433+ add_audit_hook_entry_unlocked (runtime , e );
434+ PyThread_release_lock (runtime -> audit_hooks .mutex );
435+ }
436+
415437 return 0 ;
416438}
417439
0 commit comments