@@ -172,7 +172,7 @@ _PySys_ClearAttrString(PyInterpreterState *interp,
172172
173173
174174static int
175- should_audit (PyInterpreterState * interp )
175+ should_audit_interp (PyInterpreterState * interp )
176176{
177177 /* interp must not be NULL, but test it just in case for extra safety */
178178 assert (interp != NULL );
@@ -186,10 +186,8 @@ should_audit(PyInterpreterState *interp)
186186
187187
188188static int
189- sys_audit_tuple (PyThreadState * ts , const char * event , PyObject * eventArgs )
189+ should_audit_tstate (PyThreadState * ts )
190190{
191- assert (PyTuple_Check (eventArgs ));
192-
193191 if (!ts ) {
194192 /* Audit hooks cannot be called with a NULL thread state */
195193 return 0 ;
@@ -199,18 +197,33 @@ sys_audit_tuple(PyThreadState *ts, const char *event, PyObject *eventArgs)
199197 the current Python thread state. */
200198 assert (ts == _PyThreadState_GET ());
201199
200+ /* Early exit when no hooks are registered */
201+ PyInterpreterState * is = ts -> interp ;
202+ if (!should_audit_interp (is )) {
203+ return 0 ;
204+ }
205+ return 1 ;
206+ }
207+
208+
209+ static int
210+ sys_audit_tuple (PyThreadState * ts , const char * event , PyObject * eventArgs )
211+ {
212+ // The caller check should_audit_tstate() or should_audit_interp() as soon
213+ // as possible to avoid any performance overhead if no hook was added.
214+ assert (should_audit_tstate (ts ));
215+
216+ // The caller must check via should_audit_tstate() that tstate is not NULL
217+ assert (ts != NULL );
218+
219+ assert (PyTuple_Check (eventArgs ));
220+
202221 if (event == NULL ) {
203222 _PyErr_SetString (ts , PyExc_ValueError ,
204223 "event argument must not be NULL" );
205224 return -1 ;
206225 }
207226
208- /* Early exit when no hooks are registered */
209- PyInterpreterState * is = ts -> interp ;
210- if (!should_audit (is )) {
211- return 0 ;
212- }
213-
214227 PyObject * eventName = NULL ;
215228 PyObject * hooks = NULL ;
216229 PyObject * hook = NULL ;
@@ -225,6 +238,7 @@ sys_audit_tuple(PyThreadState *ts, const char *event, PyObject *eventArgs)
225238 *
226239 * We don't worry about any races on hooks getting added,
227240 * since that would not leave is in an inconsistent state. */
241+ PyInterpreterState * is = ts -> interp ;
228242 _Py_AuditHookEntry * e = is -> runtime -> audit_hooks .head ;
229243 for (; e ; e = e -> next ) {
230244 if (e -> hookCFunction (event , eventArgs , e -> userData ) < 0 ) {
333347_PySys_Audit (PyThreadState * tstate , const char * event ,
334348 const char * format , ...)
335349{
350+ // tstate can be NULL
351+ if (!should_audit_tstate (tstate )) {
352+ return 0 ;
353+ }
354+
336355 va_list vargs ;
337356 va_start (vargs , format );
338357 int res = sys_audit_vargs (tstate , event , format , vargs );
344363PySys_Audit (const char * event , const char * format , ...)
345364{
346365 PyThreadState * tstate = _PyThreadState_GET ();
366+ // tstate can be NULL if the function is called before Py_Initialize()
367+ if (!should_audit_tstate (tstate )) {
368+ return 0 ;
369+ }
370+
347371 va_list vargs ;
348372 va_start (vargs , format );
349373 int res = sys_audit_vargs (tstate , event , format , vargs );
355379PySys_AuditTuple (const char * event , PyObject * args )
356380{
357381 PyThreadState * tstate = _PyThreadState_GET ();
358- int delete_args = 0 ;
382+ // tstate can be NULL if the function is called before Py_Initialize()
383+ if (!should_audit_tstate (tstate )) {
384+ return 0 ;
385+ }
359386
387+ int delete_args = 0 ;
360388 if (args == NULL ) {
361389 delete_args = 1 ;
362390 args = PyTuple_New (0 );
@@ -549,7 +577,7 @@ sys_audit(PyObject *self, PyObject *const *args, Py_ssize_t argc)
549577 return NULL ;
550578 }
551579
552- if (!should_audit (tstate -> interp )) {
580+ if (!should_audit_interp (tstate -> interp )) {
553581 Py_RETURN_NONE ;
554582 }
555583
0 commit comments