mirror of
https://github.com/python/cpython.git
synced 2025-10-01 04:42:10 +00:00
[3.11] gh-99110: Initialize frame->previous in init_frame to fix segmentation fault (GH-100182) (#100478)
(cherry picked from commit 88d565f32a
)
Co-authored-by: Bill Fisher <william.w.fisher@gmail.com>
This commit is contained in:
parent
b914054d9d
commit
57e727af3f
5 changed files with 35 additions and 1 deletions
|
@ -94,7 +94,10 @@ static inline void _PyFrame_StackPush(_PyInterpreterFrame *f, PyObject *value) {
|
||||||
|
|
||||||
void _PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *dest);
|
void _PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *dest);
|
||||||
|
|
||||||
/* Consumes reference to func */
|
/* Consumes reference to func and locals.
|
||||||
|
Does not initialize frame->previous, which happens
|
||||||
|
when frame is linked into the frame stack.
|
||||||
|
*/
|
||||||
static inline void
|
static inline void
|
||||||
_PyFrame_InitializeSpecials(
|
_PyFrame_InitializeSpecials(
|
||||||
_PyInterpreterFrame *frame, PyFunctionObject *func,
|
_PyInterpreterFrame *frame, PyFunctionObject *func,
|
||||||
|
|
|
@ -1335,6 +1335,16 @@ class Test_FrameAPI(unittest.TestCase):
|
||||||
frame = next(gen)
|
frame = next(gen)
|
||||||
self.assertIs(gen, _testcapi.frame_getgenerator(frame))
|
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)
|
||||||
|
|
||||||
|
|
||||||
SUFFICIENT_TO_DEOPT_AND_SPECIALIZE = 100
|
SUFFICIENT_TO_DEOPT_AND_SPECIALIZE = 100
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Initialize frame->previous in frameobject.c to fix a segmentation fault when
|
||||||
|
accessing frames created by :c:func:`PyFrame_New`.
|
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
#include "datetime.h" // PyDateTimeAPI
|
#include "datetime.h" // PyDateTimeAPI
|
||||||
|
#include "frameobject.h" // PyFrame_New
|
||||||
#include "marshal.h" // PyMarshal_WriteLongToFile
|
#include "marshal.h" // PyMarshal_WriteLongToFile
|
||||||
#include "structmember.h" // PyMemberDef
|
#include "structmember.h" // PyMemberDef
|
||||||
#include <float.h> // FLT_MAX
|
#include <float.h> // FLT_MAX
|
||||||
|
@ -6000,6 +6001,22 @@ frame_getlasti(PyObject *self, PyObject *frame)
|
||||||
return PyLong_FromLong(lasti);
|
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 *
|
static PyObject *
|
||||||
eval_get_func_name(PyObject *self, PyObject *func)
|
eval_get_func_name(PyObject *self, PyObject *func)
|
||||||
{
|
{
|
||||||
|
@ -6492,6 +6509,7 @@ static PyMethodDef TestMethods[] = {
|
||||||
{"frame_getgenerator", frame_getgenerator, METH_O, NULL},
|
{"frame_getgenerator", frame_getgenerator, METH_O, NULL},
|
||||||
{"frame_getbuiltins", frame_getbuiltins, METH_O, NULL},
|
{"frame_getbuiltins", frame_getbuiltins, METH_O, NULL},
|
||||||
{"frame_getlasti", frame_getlasti, METH_O, NULL},
|
{"frame_getlasti", frame_getlasti, METH_O, NULL},
|
||||||
|
{"frame_new", frame_new, METH_VARARGS, NULL},
|
||||||
{"eval_get_func_name", eval_get_func_name, METH_O, NULL},
|
{"eval_get_func_name", eval_get_func_name, METH_O, NULL},
|
||||||
{"eval_get_func_desc", eval_get_func_desc, METH_O, NULL},
|
{"eval_get_func_desc", eval_get_func_desc, METH_O, NULL},
|
||||||
{"get_feature_macros", get_feature_macros, METH_NOARGS, NULL},
|
{"get_feature_macros", get_feature_macros, METH_NOARGS, NULL},
|
||||||
|
|
|
@ -1010,6 +1010,7 @@ init_frame(_PyInterpreterFrame *frame, PyFunctionObject *func, PyObject *locals)
|
||||||
Py_INCREF(func);
|
Py_INCREF(func);
|
||||||
PyCodeObject *code = (PyCodeObject *)func->func_code;
|
PyCodeObject *code = (PyCodeObject *)func->func_code;
|
||||||
_PyFrame_InitializeSpecials(frame, func, locals, code->co_nlocalsplus);
|
_PyFrame_InitializeSpecials(frame, func, locals, code->co_nlocalsplus);
|
||||||
|
frame->previous = NULL;
|
||||||
for (Py_ssize_t i = 0; i < code->co_nlocalsplus; i++) {
|
for (Py_ssize_t i = 0; i < code->co_nlocalsplus; i++) {
|
||||||
frame->localsplus[i] = NULL;
|
frame->localsplus[i] = NULL;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue