Skip to content
1 change: 1 addition & 0 deletions Include/internal/pycore_frame.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ _PyFrame_InitializeSpecials(
frame->prev_instr = _PyCode_CODE(code) - 1;
frame->yield_offset = 0;
frame->owner = FRAME_OWNED_BY_THREAD;
// frame->previous: initialized when frame is linked into the frame stack
Comment thread
kumaraditya303 marked this conversation as resolved.
Outdated
}

/* Gets the pointer to the locals array
Expand Down
31 changes: 31 additions & 0 deletions Lib/test/test_ctypes/test_python_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,5 +81,36 @@ def test_pyobject_repr(self):
self.assertEqual(repr(py_object(42)), "py_object(42)")
self.assertEqual(repr(py_object(object)), "py_object(%r)" % object)

def test_PyFrame_New_f_back(self):
Comment thread
kumaraditya303 marked this conversation as resolved.
Outdated
"""Test that accessing `f_back` does not cause a segmentation fault on
a frame created with ctypes (GH-99110)."""
# Adapted from:
# https://naleraphael.github.io/blog/posts/devlog_create_a_builtin_frame_object/

p_memtype = POINTER(c_ulong if sizeof(c_void_p) == 8 else c_uint)
pythonapi.PyFrame_New.argtypes = (
p_memtype, # PyThreadState *tstate
p_memtype, # PyCodeObject *code
py_object, # PyObject *globals
py_object # PyObject *locals
)
pythonapi.PyFrame_New.restype = py_object # PyFrameObject*
pythonapi.PyThreadState_Get.argtypes = None
pythonapi.PyThreadState_Get.restype = p_memtype

def dummy():
pass

frame = pythonapi.PyFrame_New(
pythonapi.PyThreadState_Get(), # thread state
cast(id(dummy.__code__), p_memtype), # a code object
globals(),
locals(),
)

# The following line should not cause a segmentation fault.
self.assertEqual(frame.f_back, None)


if __name__ == "__main__":
unittest.main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Initialize frame->previous in frameobject.c to fix a segmentation fault when
accessing frames created by ctypes.
Comment thread
kumaraditya303 marked this conversation as resolved.
Outdated
1 change: 1 addition & 0 deletions Objects/frameobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -1013,6 +1013,7 @@ init_frame(_PyInterpreterFrame *frame, PyFunctionObject *func, PyObject *locals)
PyCodeObject *code = (PyCodeObject *)func->func_code;
_PyFrame_InitializeSpecials(frame, (PyFunctionObject*)Py_NewRef(func),
Py_XNewRef(locals), code);
frame->previous = NULL;
for (Py_ssize_t i = 0; i < code->co_nlocalsplus; i++) {
frame->localsplus[i] = NULL;
}
Expand Down