10000 Exit ASAP if no audit hook was added · python/cpython@cb25901 · GitHub
[go: up one dir, main page]

Skip to content

Commit cb25901

Browse files
committed
Exit ASAP if no audit hook was added
Avoid any performance overhead when no hook was added. Enhance also test_audit_tuple(): add a hook and reuse "sawSet" test.
1 parent 528ac80 commit cb25901

File tree

2 files changed

+48
-14
lines changed

2 files changed

+48
-14
lines changed

Programs/_testembed.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1314,18 +1314,24 @@ static int test_audit(void)
13141314

13151315
static int test_audit_tuple(void)
13161316
{
1317+
Py_ssize_t sawSet = 0;
1318+
1319+
// we need at least one hook, otherwise code checking for
1320+
// PySys_AuditTuple() is skipped.
1321+
PySys_AddAuditHook(_audit_hook, &sawSet);
13171322
_testembed_Py_InitializeFromConfig();
13181323

13191324
assert(!PyErr_Occurred());
13201325

13211326
// pass tuple
1322-
PyObject *tuple = Py_BuildValue("ii", 3, 5);
1327+
PyObject *tuple = Py_BuildValue("(i)", 444);
13231328
if (tuple == NULL) {
13241329
goto error;
13251330
}
1326-
assert(PySys_AuditTuple("_testembed.test_audit_tuple", tuple) == 0);
1331+
assert(PySys_AuditTuple("_testembed.set", tuple) == 0);
13271332
assert(!PyErr_Occurred());
13281333
Py_DECREF(tuple);
1334+
assert(sawSet == 444);
13291335

13301336
// NULL is accepted and means "no arguments"
13311337
assert(PySys_AuditTuple("_testembed.test_audit_tuple", NULL) == 0);

Python/sysmodule.c

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ _PySys_ClearAttrString(PyInterpreterState *interp,
171171

172172

173173
static int
174-
should_audit(PyInterpreterState *interp)
174+
should_audit_interp(PyInterpreterState *interp)
175175
{
176176
/* interp must not be NULL, but test it just in case for extra safety */
177177
assert(interp != NULL);
@@ -185,10 +185,8 @@ should_audit(PyInterpreterState *interp)
185185

186186

187187
static int
188-
sys_audit_tuple(PyThreadState *ts, const char *event, PyObject *eventArgs)
188+
should_audit_tstate(PyThreadState *ts)
189189
{
190-
assert(PyTuple_Check(eventArgs));
191-
192190
if (!ts) {
193191
/* Audit hooks cannot be called with a NULL thread state */
194192
return 0;
@@ -198,18 +196,33 @@ sys_audit_tuple(PyThreadState *ts, const char *event, PyObject *eventArgs)
198196
the current Python thread state. */
199197
assert(ts == _PyThreadState_GET());
200198

199+
/* Early exit when no hooks are registered */
200+
PyInterpreterState *is = ts->interp;
201+
if (!should_audit_interp(is)) {
202+
return 0;
203+
}
204+
return 1;
205+
}
206+
207+
208+
static int
209+
sys_audit_tuple(PyThreadState *ts, const char *event, PyObject *eventArgs)
210+
{
211+
// The caller check should_audit_tstate() or should_audit_interp() as soon
212+
// as possible to avoid any performance overhead if no hook was added.
213+
assert(should_audit_tstate(ts));
214+
215+
// The caller must check via should_audit_tstate() that tstate is not NULL
216+
assert(ts != NULL);
217+
218+
assert(PyTuple_Check(eventArgs));
219+
201220
if (event == NULL) {
202221
_PyErr_SetString(ts, PyExc_ValueError,
203222
"event argument must not be NULL");
204223
return -1;
205224
}
206225

207-
/* Early exit when no hooks are registered */
208-
PyInterpreterState *is = ts->interp;
209-
if (!should_audit(is)) {
210-
return 0;
211-
}
212-
213226
PyObject *eventName = NULL;
214227
PyObject *hooks = NULL;
215228
PyObject *hook = NULL;
@@ -224,6 +237,7 @@ sys_audit_tuple(PyThreadState *ts, const char *event, PyObject *eventArgs)
224237
*
225238
* We don't worry about any races on hooks getting added,
226239
* since that would not leave is in an inconsistent state. */
240+
PyInterpreterState *is = ts->interp;
227241
_Py_AuditHookEntry *e = is->runtime->audit_hooks.head;
228242
for (; e; e = e->next) {
229243
if (e->hookCFunction(event, eventArgs, e->userData) < 0) {
@@ -332,6 +346,11 @@ int
332346
_PySys_Audit(PyThreadState *tstate, const char *event,
333347
const char *format, ...)
334348
{
349+
// tstate can be NULL
350+
if (!should_audit_tstate(tstate)) {
351+
return 0;
352+
}
353+
335354
va_list vargs;
336355
va_start(vargs, format);
337356
int res = sys_audit_vargs(tstate, event, format, vargs);
@@ -343,6 +362,11 @@ int
343362
PySys_Audit(const char *event, const char *format, ...)
344363
{
345364
PyThreadState *tstate = _PyThreadState_GET();
365+
// tstate can be NULL if the function is called before Py_Initialize()
366+
if (!should_audit_tstate(tstate)) {
367+
return 0;
368+
}
369+
346370
va_list vargs;
347371
va_start(vargs, format);
348372
int res = sys_audit_vargs(tstate, event, format, vargs);
@@ -354,8 +378,12 @@ int
354378
PySys_AuditTuple(const char *event, PyObject *args)
355379
{
356380
PyThreadState *tstate = _PyThreadState_GET();
357-
int delete_args = 0;
381+
// tstate can be NULL if the function is called before Py_Initialize()
382+
if (!should_audit_tstate(tstate)) {
383+
return 0;
384+
}
358385

386+
int delete_args = 0;
359387
if (args == NULL) {
360388
delete_args = 1;
361389
args = PyTuple_New(0);
@@ -548,7 +576,7 @@ sys_audit(PyObject *self, PyObject *const *args, Py_ssize_t argc)
548576
return NULL;
549577
}
550578

551-
if (!should_audit(tstate->interp)) {
579+
if (!should_audit_interp(tstate->interp)) {
552580
Py_RETURN_NONE;
553581
}
554582

0 commit comments

Comments
 (0)
0