Closed
Description
Bug report
Bug description:
Given a setup.py
with:
from setuptools import Extension
from setuptools import setup
setup(
name="testext",
version="0.0",
ext_modules=[
Extension("testext", language="c++", sources=["testext.cpp"]),
],
zip_safe=False,
)
and a testext.cpp
with:
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <assert.h>
#include <pthread.h>
#include <unistd.h>
int tracefunc(PyObject *, PyFrameObject *, int, PyObject *)
{
return 0;
}
void*
thread_body(void*)
{
PyGILState_STATE gilstate = PyGILState_Ensure();
PyEval_SetTrace(&tracefunc, Py_None);
PyGILState_Release(gilstate);
return NULL;
}
PyObject*
trace_in_thread(PyObject*, PyObject*)
{
pthread_t thread;
int ret = pthread_create(&thread, NULL, &thread_body, NULL);
assert(0 == ret);
Py_BEGIN_ALLOW_THREADS
ret = pthread_join(thread, NULL);
assert(0 == ret);
Py_END_ALLOW_THREADS
Py_RETURN_NONE;
}
static PyMethodDef methods[] = {
{"trace_in_thread", trace_in_thread, METH_NOARGS, "Call PyEval_SetTrace in a thread"},
{NULL, NULL, 0, NULL},
};
static struct PyModuleDef moduledef = {PyModuleDef_HEAD_INIT, "testext", "", -1, methods};
PyMODINIT_FUNC
PyInit_testext(void)
{
return PyModule_Create(&moduledef);
}
doing:
python3.13 -m pip install .
python3.13 -c 'import testext; testext.trace_in_thread()'
gives a segmentation fault, because of this code in _PyEval_SetTrace
:
cpython/Python/legacy_tracing.c
Lines 607 to 608 in 7b41395
This reproducer enters _PyEval_SetTrace
with no Python frames on the stack, and so PyEval_GetFrame
returns a null pointer and frame->f_trace_opcodes
dereferences it. It seems that this needs to be guarded:
PyFrameObject* frame = PyEval_GetFrame();
if (frame && frame->f_trace_opcodes) {
CPython versions tested on:
3.13
Operating systems tested on:
Linux