profile function is called for all monitored events except :const:`PyTrace_LINE`
:const:`PyTrace_OPCODE` and :const:`PyTrace_EXCEPTION`.
+ The caller must hold the :term:`GIL`.
+
.. c:function:: void PyEval_SetTrace(Py_tracefunc func, PyObject *obj)
will not receive :const:`PyTrace_C_CALL`, :const:`PyTrace_C_EXCEPTION` or
:const:`PyTrace_C_RETURN` as a value for the *what* parameter.
+ The caller must hold the :term:`GIL`.
+
+
.. _advanced-debugging:
Advanced Debugger Support
"tuple" and keyword arguments "dict". "dict" may also be NULL */
PyAPI_FUNC(PyObject *) PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *dict);
+static inline PyObject *
+_PyObject_FastCallTstate(PyThreadState *tstate, PyObject *func, PyObject *const *args, Py_ssize_t nargs)
+{
+ return _PyObject_VectorcallTstate(tstate, func, args, (size_t)nargs, NULL);
+}
+
/* Same as PyObject_Vectorcall except without keyword arguments */
static inline PyObject *
_PyObject_FastCall(PyObject *func, PyObject *const *args, Py_ssize_t nargs)
{
PyThreadState *tstate = PyThreadState_GET();
- return _PyObject_VectorcallTstate(tstate, func, args, (size_t)nargs, NULL);
+ return _PyObject_FastCallTstate(tstate, func, args, nargs);
}
/* Call a callable without any arguments
#endif
PyAPI_FUNC(void) PyEval_SetProfile(Py_tracefunc, PyObject *);
+PyAPI_DATA(int) _PyEval_SetProfile(PyThreadState *tstate, Py_tracefunc func, PyObject *arg);
PyAPI_FUNC(void) PyEval_SetTrace(Py_tracefunc, PyObject *);
+PyAPI_FUNC(int) _PyEval_SetTrace(PyThreadState *tstate, Py_tracefunc func, PyObject *arg);
PyAPI_FUNC(int) _PyEval_GetCoroutineOriginTrackingDepth(void);
PyAPI_FUNC(void) _PyEval_SetAsyncGenFirstiter(PyObject *);
PyAPI_FUNC(PyObject *) _PyEval_GetAsyncGenFirstiter(void);
--- /dev/null
+sys.settrace(), sys.setprofile() and _lsprof.Profiler.enable() now properly
+report :c:func:`PySys_Audit` error if "sys.setprofile" or "sys.settrace"
+audit event is denied.
profiler_getstats(ProfilerObject *pObj, PyObject* noarg)
{
statscollector_t collect;
- if (pending_exception(pObj))
+ if (pending_exception(pObj)) {
return NULL;
+ }
if (!pObj->externalTimer || pObj->externalTimerUnit == 0.0) {
_PyTime_t onesec = _PyTime_FromSeconds(1);
collect.factor = (double)1 / onesec;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii:enable",
kwlist, &subcalls, &builtins))
return NULL;
- if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0)
+ if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0) {
+ return NULL;
+ }
+
+ PyThreadState *tstate = PyThreadState_GET();
+ if (_PyEval_SetProfile(tstate, profiler_callback, (PyObject*)self) < 0) {
return NULL;
- PyEval_SetProfile(profiler_callback, (PyObject*)self);
+ }
+
self->flags |= POF_ENABLED;
Py_RETURN_NONE;
}
static PyObject*
profiler_disable(ProfilerObject *self, PyObject* noarg)
{
+ PyThreadState *tstate = PyThreadState_GET();
+ if (_PyEval_SetProfile(tstate, NULL, NULL) < 0) {
+ return NULL;
+ }
self->flags &= ~POF_ENABLED;
- PyEval_SetProfile(NULL, NULL);
+
flush_unmatched(self);
- if (pending_exception(self))
+ if (pending_exception(self)) {
return NULL;
+ }
Py_RETURN_NONE;
}
static void
profiler_dealloc(ProfilerObject *op)
{
- if (op->flags & POF_ENABLED)
- PyEval_SetProfile(NULL, NULL);
+ if (op->flags & POF_ENABLED) {
+ PyThreadState *tstate = PyThreadState_GET();
+ if (_PyEval_SetProfile(tstate, NULL, NULL) < 0) {
+ PyErr_WriteUnraisable((PyObject *)op);
+ }
+ }
+
flush_unmatched(op);
clearEntries(op);
Py_XDECREF(op->externalTimer);
return result;
}
-void
-PyEval_SetProfile(Py_tracefunc func, PyObject *arg)
+int
+_PyEval_SetProfile(PyThreadState *tstate, Py_tracefunc func, PyObject *arg)
{
+ assert(tstate != NULL);
+ /* The caller must hold the GIL */
+ assert(PyGILState_Check());
+
+ /* Call PySys_Audit() in the context of the current thread state,
+ even if tstate is not the current thread state. */
if (PySys_Audit("sys.setprofile", NULL) < 0) {
- return;
+ return -1;
}
- PyThreadState *tstate = _PyThreadState_GET();
- PyObject *temp = tstate->c_profileobj;
- Py_XINCREF(arg);
+ PyObject *profileobj = tstate->c_profileobj;
+
tstate->c_profilefunc = NULL;
tstate->c_profileobj = NULL;
- /* Must make sure that tracing is not ignored if 'temp' is freed */
+ /* Must make sure that tracing is not ignored if 'profileobj' is freed */
tstate->use_tracing = tstate->c_tracefunc != NULL;
- Py_XDECREF(temp);
- tstate->c_profilefunc = func;
+ Py_XDECREF(profileobj);
+
+ Py_XINCREF(arg);
tstate->c_profileobj = arg;
+ tstate->c_profilefunc = func;
+
/* Flag that tracing or profiling is turned on */
tstate->use_tracing = (func != NULL) || (tstate->c_tracefunc != NULL);
+ return 0;
}
void
-PyEval_SetTrace(Py_tracefunc func, PyObject *arg)
+PyEval_SetProfile(Py_tracefunc func, PyObject *arg)
+{
+ PyThreadState *tstate = _PyThreadState_GET();
+ (void)_PyEval_SetProfile(tstate, func, arg);
+}
+
+int
+_PyEval_SetTrace(PyThreadState *tstate, Py_tracefunc func, PyObject *arg)
{
+ assert(tstate != NULL);
+ /* The caller must hold the GIL */
+ assert(PyGILState_Check());
+
+ /* Call PySys_Audit() in the context of the current thread state,
+ even if tstate is not the current thread state. */
if (PySys_Audit("sys.settrace", NULL) < 0) {
- return;
+ return -1;
}
- _PyRuntimeState *runtime = &_PyRuntime;
- PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime);
- PyObject *temp = tstate->c_traceobj;
- runtime->ceval.tracing_possible += (func != NULL) - (tstate->c_tracefunc != NULL);
- Py_XINCREF(arg);
+ struct _ceval_runtime_state *ceval = &tstate->interp->runtime->ceval;
+ PyObject *traceobj = tstate->c_traceobj;
+ ceval->tracing_possible += (func != NULL) - (tstate->c_tracefunc != NULL);
+
tstate->c_tracefunc = NULL;
tstate->c_traceobj = NULL;
- /* Must make sure that profiling is not ignored if 'temp' is freed */
- tstate->use_tracing = tstate->c_profilefunc != NULL;
- Py_XDECREF(temp);
- tstate->c_tracefunc = func;
+ /* Must make sure that profiling is not ignored if 'traceobj' is freed */
+ tstate->use_tracing = (tstate->c_profilefunc != NULL);
+ Py_XDECREF(traceobj);
+
+ Py_XINCREF(arg);
tstate->c_traceobj = arg;
+ tstate->c_tracefunc = func;
+
/* Flag that tracing or profiling is turned on */
tstate->use_tracing = ((func != NULL)
|| (tstate->c_profilefunc != NULL));
+
+ return 0;
+}
+
+void
+PyEval_SetTrace(Py_tracefunc func, PyObject *arg)
+{
+ PyThreadState *tstate = _PyThreadState_GET();
+ (void)_PyEval_SetTrace(tstate, func, arg);
}
+
void
_PyEval_SetCoroutineOriginTrackingDepth(PyThreadState *tstate, int new_depth)
{
static PyObject *
-call_trampoline(PyObject* callback,
+call_trampoline(PyThreadState *tstate, PyObject* callback,
PyFrameObject *frame, int what, PyObject *arg)
{
if (PyFrame_FastToLocalsWithError(frame) < 0) {
stack[2] = (arg != NULL) ? arg : Py_None;
/* call the Python-level function */
- PyObject *result = _PyObject_FastCall(callback, stack, 3);
+ PyObject *result = _PyObject_FastCallTstate(tstate, callback, stack, 3);
PyFrame_LocalsToFast(frame, 1);
if (result == NULL) {
profile_trampoline(PyObject *self, PyFrameObject *frame,
int what, PyObject *arg)
{
- PyObject *result;
-
- if (arg == NULL)
+ if (arg == NULL) {
arg = Py_None;
- result = call_trampoline(self, frame, what, arg);
+ }
+
+ PyThreadState *tstate = _PyThreadState_GET();
+ PyObject *result = call_trampoline(tstate, self, frame, what, arg);
if (result == NULL) {
- PyEval_SetProfile(NULL, NULL);
+ _PyEval_SetProfile(tstate, NULL, NULL);
return -1;
}
+
Py_DECREF(result);
return 0;
}
int what, PyObject *arg)
{
PyObject *callback;
- PyObject *result;
-
- if (what == PyTrace_CALL)
+ if (what == PyTrace_CALL) {
callback = self;
- else
+ }
+ else {
callback = frame->f_trace;
- if (callback == NULL)
+ }
+ if (callback == NULL) {
return 0;
- result = call_trampoline(callback, frame, what, arg);
+ }
+
+ PyThreadState *tstate = _PyThreadState_GET();
+ PyObject *result = call_trampoline(tstate, callback, frame, what, arg);
if (result == NULL) {
- PyEval_SetTrace(NULL, NULL);
+ _PyEval_SetTrace(tstate, NULL, NULL);
Py_CLEAR(frame->f_trace);
return -1;
}
+
if (result != Py_None) {
Py_XSETREF(frame->f_trace, result);
}
static PyObject *
sys_settrace(PyObject *self, PyObject *args)
{
- if (trace_init() == -1)
+ if (trace_init() == -1) {
return NULL;
- if (args == Py_None)
- PyEval_SetTrace(NULL, NULL);
- else
- PyEval_SetTrace(trace_trampoline, args);
+ }
+
+ PyThreadState *tstate = _PyThreadState_GET();
+ if (args == Py_None) {
+ if (_PyEval_SetTrace(tstate, NULL, NULL) < 0) {
+ return NULL;
+ }
+ }
+ else {
+ if (_PyEval_SetTrace(tstate, trace_trampoline, args) < 0) {
+ return NULL;
+ }
+ }
Py_RETURN_NONE;
}
static PyObject *
sys_setprofile(PyObject *self, PyObject *args)
{
- if (trace_init() == -1)
+ if (trace_init() == -1) {
return NULL;
- if (args == Py_None)
- PyEval_SetProfile(NULL, NULL);
- else
- PyEval_SetProfile(profile_trampoline, args);
+ }
+
+ PyThreadState *tstate = _PyThreadState_GET();
+ if (args == Py_None) {
+ if (_PyEval_SetProfile(tstate, NULL, NULL) < 0) {
+ return NULL;
+ }
+ }
+ else {
+ if (_PyEval_SetProfile(tstate, profile_trampoline, args) < 0) {
+ return NULL;
+ }
+ }
Py_RETURN_NONE;
}