mirror of
https://github.com/python/cpython
synced 2024-10-05 05:28:25 +00:00
gh-99110: Initialize frame->previous
in init_frame to fix segmentation fault when accessing frame.f_back
(#100182)
This commit is contained in:
parent
2659036c75
commit
88d565f32a
|
@ -96,7 +96,10 @@ static inline void _PyFrame_StackPush(_PyInterpreterFrame *f, PyObject *value) {
|
|||
|
||||
void _PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *dest);
|
||||
|
||||
/* Consumes reference to func and locals */
|
||||
/* Consumes reference to func and locals.
|
||||
Does not initialize frame->previous, which happens
|
||||
when frame is linked into the frame stack.
|
||||
*/
|
||||
static inline void
|
||||
_PyFrame_InitializeSpecials(
|
||||
_PyInterpreterFrame *frame, PyFunctionObject *func,
|
||||
|
|
|
@ -408,6 +408,15 @@ def test_frame_get_generator(self):
|
|||
frame = next(gen)
|
||||
self.assertIs(gen, _testcapi.frame_getgenerator(frame))
|
||||
|
||||
def test_frame_fback_api(self):
|
||||
"""Test that accessing `f_back` does not cause a segmentation fault on
|
||||
a frame created with `PyFrame_New` (GH-99110)."""
|
||||
def dummy():
|
||||
pass
|
||||
|
||||
frame = _testcapi.frame_new(dummy.__code__, globals(), locals())
|
||||
# The following line should not cause a segmentation fault.
|
||||
self.assertIsNone(frame.f_back)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Initialize frame->previous in frameobject.c to fix a segmentation fault when
|
||||
accessing frames created by :c:func:`PyFrame_New`.
|
|
@ -20,6 +20,7 @@
|
|||
#define PY_SSIZE_T_CLEAN
|
||||
|
||||
#include "Python.h"
|
||||
#include "frameobject.h" // PyFrame_New
|
||||
#include "marshal.h" // PyMarshal_WriteLongToFile
|
||||
#include "structmember.h" // for offsetof(), T_OBJECT
|
||||
#include <float.h> // FLT_MAX
|
||||
|
@ -2839,6 +2840,22 @@ frame_getlasti(PyObject *self, PyObject *frame)
|
|||
return PyLong_FromLong(lasti);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
frame_new(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *code, *globals, *locals;
|
||||
if (!PyArg_ParseTuple(args, "OOO", &code, &globals, &locals)) {
|
||||
return NULL;
|
||||
}
|
||||
if (!PyCode_Check(code)) {
|
||||
PyErr_SetString(PyExc_TypeError, "argument must be a code object");
|
||||
return NULL;
|
||||
}
|
||||
PyThreadState *tstate = PyThreadState_Get();
|
||||
|
||||
return (PyObject *)PyFrame_New(tstate, (PyCodeObject *)code, globals, locals);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
test_frame_getvar(PyObject *self, PyObject *args)
|
||||
{
|
||||
|
@ -3277,6 +3294,7 @@ static PyMethodDef TestMethods[] = {
|
|||
{"frame_getgenerator", frame_getgenerator, METH_O, NULL},
|
||||
{"frame_getbuiltins", frame_getbuiltins, METH_O, NULL},
|
||||
{"frame_getlasti", frame_getlasti, METH_O, NULL},
|
||||
{"frame_new", frame_new, METH_VARARGS, NULL},
|
||||
{"frame_getvar", test_frame_getvar, METH_VARARGS, NULL},
|
||||
{"frame_getvarstring", test_frame_getvarstring, METH_VARARGS, NULL},
|
||||
{"eval_get_func_name", eval_get_func_name, METH_O, NULL},
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue