Issue #18408: Add a new PyFrame_FastToLocalsWithError() function to handle
exceptions when merging fast locals into f_locals of a frame. PyEval_GetLocals() now raises an exception and return NULL on failure.
This commit is contained in:
parent
28c63f7ffb
commit
41bb43a71e
|
@ -78,6 +78,8 @@ PyAPI_FUNC(PyObject **) PyFrame_ExtendStack(PyFrameObject *, int, int);
|
||||||
/* Conversions between "fast locals" and locals in dictionary */
|
/* Conversions between "fast locals" and locals in dictionary */
|
||||||
|
|
||||||
PyAPI_FUNC(void) PyFrame_LocalsToFast(PyFrameObject *, int);
|
PyAPI_FUNC(void) PyFrame_LocalsToFast(PyFrameObject *, int);
|
||||||
|
|
||||||
|
PyAPI_FUNC(int) PyFrame_FastToLocalsWithError(PyFrameObject *f);
|
||||||
PyAPI_FUNC(void) PyFrame_FastToLocals(PyFrameObject *);
|
PyAPI_FUNC(void) PyFrame_FastToLocals(PyFrameObject *);
|
||||||
|
|
||||||
PyAPI_FUNC(int) PyFrame_ClearFreeList(void);
|
PyAPI_FUNC(int) PyFrame_ClearFreeList(void);
|
||||||
|
|
|
@ -10,6 +10,10 @@ Projected release date: 2013-11-24
|
||||||
Core and Builtins
|
Core and Builtins
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Issue #18408: Add a new PyFrame_FastToLocalsWithError() function to handle
|
||||||
|
exceptions when merging fast locals into f_locals of a frame.
|
||||||
|
PyEval_GetLocals() now raises an exception and return NULL on failure.
|
||||||
|
|
||||||
- Issue #19369: Optimized the usage of __length_hint__().
|
- Issue #19369: Optimized the usage of __length_hint__().
|
||||||
|
|
||||||
- Issue #18603: Ensure that PyOS_mystricmp and PyOS_mystrnicmp are in the
|
- Issue #18603: Ensure that PyOS_mystricmp and PyOS_mystrnicmp are in the
|
||||||
|
|
|
@ -21,7 +21,8 @@ static PyMemberDef frame_memberlist[] = {
|
||||||
static PyObject *
|
static PyObject *
|
||||||
frame_getlocals(PyFrameObject *f, void *closure)
|
frame_getlocals(PyFrameObject *f, void *closure)
|
||||||
{
|
{
|
||||||
PyFrame_FastToLocals(f);
|
if (PyFrame_FastToLocalsWithError(f) < 0)
|
||||||
|
return NULL;
|
||||||
Py_INCREF(f->f_locals);
|
Py_INCREF(f->f_locals);
|
||||||
return f->f_locals;
|
return f->f_locals;
|
||||||
}
|
}
|
||||||
|
@ -772,12 +773,9 @@ PyFrame_BlockPop(PyFrameObject *f)
|
||||||
If deref is true, then the values being copied are cell variables
|
If deref is true, then the values being copied are cell variables
|
||||||
and the value is extracted from the cell variable before being put
|
and the value is extracted from the cell variable before being put
|
||||||
in dict.
|
in dict.
|
||||||
|
|
||||||
Exceptions raised while modifying the dict are silently ignored,
|
|
||||||
because there is no good way to report them.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void
|
static int
|
||||||
map_to_dict(PyObject *map, Py_ssize_t nmap, PyObject *dict, PyObject **values,
|
map_to_dict(PyObject *map, Py_ssize_t nmap, PyObject *dict, PyObject **values,
|
||||||
int deref)
|
int deref)
|
||||||
{
|
{
|
||||||
|
@ -794,14 +792,19 @@ map_to_dict(PyObject *map, Py_ssize_t nmap, PyObject *dict, PyObject **values,
|
||||||
value = PyCell_GET(value);
|
value = PyCell_GET(value);
|
||||||
}
|
}
|
||||||
if (value == NULL) {
|
if (value == NULL) {
|
||||||
if (PyObject_DelItem(dict, key) != 0)
|
if (PyObject_DelItem(dict, key) != 0) {
|
||||||
PyErr_Clear();
|
if (PyErr_ExceptionMatches(PyExc_KeyError))
|
||||||
|
PyErr_Clear();
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (PyObject_SetItem(dict, key, value) != 0)
|
if (PyObject_SetItem(dict, key, value) != 0)
|
||||||
PyErr_Clear();
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy values from the "locals" dict into the fast locals.
|
/* Copy values from the "locals" dict into the fast locals.
|
||||||
|
@ -858,42 +861,49 @@ dict_to_map(PyObject *map, Py_ssize_t nmap, PyObject *dict, PyObject **values,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
int
|
||||||
PyFrame_FastToLocals(PyFrameObject *f)
|
PyFrame_FastToLocalsWithError(PyFrameObject *f)
|
||||||
{
|
{
|
||||||
/* Merge fast locals into f->f_locals */
|
/* Merge fast locals into f->f_locals */
|
||||||
PyObject *locals, *map;
|
PyObject *locals, *map;
|
||||||
PyObject **fast;
|
PyObject **fast;
|
||||||
PyObject *error_type, *error_value, *error_traceback;
|
|
||||||
PyCodeObject *co;
|
PyCodeObject *co;
|
||||||
Py_ssize_t j;
|
Py_ssize_t j;
|
||||||
Py_ssize_t ncells, nfreevars;
|
Py_ssize_t ncells, nfreevars;
|
||||||
if (f == NULL)
|
|
||||||
return;
|
if (f == NULL) {
|
||||||
|
PyErr_BadInternalCall();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
locals = f->f_locals;
|
locals = f->f_locals;
|
||||||
if (locals == NULL) {
|
if (locals == NULL) {
|
||||||
locals = f->f_locals = PyDict_New();
|
locals = f->f_locals = PyDict_New();
|
||||||
if (locals == NULL) {
|
if (locals == NULL)
|
||||||
PyErr_Clear(); /* Can't report it :-( */
|
return -1;
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
co = f->f_code;
|
co = f->f_code;
|
||||||
map = co->co_varnames;
|
map = co->co_varnames;
|
||||||
if (!PyTuple_Check(map))
|
if (!PyTuple_Check(map)) {
|
||||||
return;
|
PyErr_Format(PyExc_SystemError,
|
||||||
PyErr_Fetch(&error_type, &error_value, &error_traceback);
|
"co_varnames must be a tuple, not %s",
|
||||||
|
Py_TYPE(map)->tp_name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
fast = f->f_localsplus;
|
fast = f->f_localsplus;
|
||||||
j = PyTuple_GET_SIZE(map);
|
j = PyTuple_GET_SIZE(map);
|
||||||
if (j > co->co_nlocals)
|
if (j > co->co_nlocals)
|
||||||
j = co->co_nlocals;
|
j = co->co_nlocals;
|
||||||
if (co->co_nlocals)
|
if (co->co_nlocals) {
|
||||||
map_to_dict(map, j, locals, fast, 0);
|
if (map_to_dict(map, j, locals, fast, 0) < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
ncells = PyTuple_GET_SIZE(co->co_cellvars);
|
ncells = PyTuple_GET_SIZE(co->co_cellvars);
|
||||||
nfreevars = PyTuple_GET_SIZE(co->co_freevars);
|
nfreevars = PyTuple_GET_SIZE(co->co_freevars);
|
||||||
if (ncells || nfreevars) {
|
if (ncells || nfreevars) {
|
||||||
map_to_dict(co->co_cellvars, ncells,
|
if (map_to_dict(co->co_cellvars, ncells,
|
||||||
locals, fast + co->co_nlocals, 1);
|
locals, fast + co->co_nlocals, 1))
|
||||||
|
return -1;
|
||||||
|
|
||||||
/* If the namespace is unoptimized, then one of the
|
/* If the namespace is unoptimized, then one of the
|
||||||
following cases applies:
|
following cases applies:
|
||||||
1. It does not contain free variables, because it
|
1. It does not contain free variables, because it
|
||||||
|
@ -903,11 +913,24 @@ PyFrame_FastToLocals(PyFrameObject *f)
|
||||||
into the locals dict used by the class.
|
into the locals dict used by the class.
|
||||||
*/
|
*/
|
||||||
if (co->co_flags & CO_OPTIMIZED) {
|
if (co->co_flags & CO_OPTIMIZED) {
|
||||||
map_to_dict(co->co_freevars, nfreevars,
|
if (map_to_dict(co->co_freevars, nfreevars,
|
||||||
locals, fast + co->co_nlocals + ncells, 1);
|
locals, fast + co->co_nlocals + ncells, 1) < 0)
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PyErr_Restore(error_type, error_value, error_traceback);
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PyFrame_FastToLocals(PyFrameObject *f)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
assert(!PyErr_Occurred());
|
||||||
|
|
||||||
|
res = PyFrame_FastToLocalsWithError(f);
|
||||||
|
if (res < 0)
|
||||||
|
PyErr_Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -1407,12 +1407,11 @@ static PyObject *
|
||||||
_dir_locals(void)
|
_dir_locals(void)
|
||||||
{
|
{
|
||||||
PyObject *names;
|
PyObject *names;
|
||||||
PyObject *locals = PyEval_GetLocals();
|
PyObject *locals;
|
||||||
|
|
||||||
if (locals == NULL) {
|
locals = PyEval_GetLocals();
|
||||||
PyErr_SetString(PyExc_SystemError, "frame does not exist");
|
if (locals == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
|
|
||||||
names = PyMapping_Keys(locals);
|
names = PyMapping_Keys(locals);
|
||||||
if (!names)
|
if (!names)
|
||||||
|
|
|
@ -755,8 +755,11 @@ builtin_eval(PyObject *self, PyObject *args)
|
||||||
}
|
}
|
||||||
if (globals == Py_None) {
|
if (globals == Py_None) {
|
||||||
globals = PyEval_GetGlobals();
|
globals = PyEval_GetGlobals();
|
||||||
if (locals == Py_None)
|
if (locals == Py_None) {
|
||||||
locals = PyEval_GetLocals();
|
locals = PyEval_GetLocals();
|
||||||
|
if (locals == NULL)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (locals == Py_None)
|
else if (locals == Py_None)
|
||||||
locals = globals;
|
locals = globals;
|
||||||
|
@ -820,6 +823,8 @@ builtin_exec(PyObject *self, PyObject *args)
|
||||||
globals = PyEval_GetGlobals();
|
globals = PyEval_GetGlobals();
|
||||||
if (locals == Py_None) {
|
if (locals == Py_None) {
|
||||||
locals = PyEval_GetLocals();
|
locals = PyEval_GetLocals();
|
||||||
|
if (locals == NULL)
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
if (!globals || !locals) {
|
if (!globals || !locals) {
|
||||||
PyErr_SetString(PyExc_SystemError,
|
PyErr_SetString(PyExc_SystemError,
|
||||||
|
@ -1926,13 +1931,9 @@ builtin_vars(PyObject *self, PyObject *args)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (v == NULL) {
|
if (v == NULL) {
|
||||||
d = PyEval_GetLocals();
|
d = PyEval_GetLocals();
|
||||||
if (d == NULL) {
|
if (d == NULL)
|
||||||
if (!PyErr_Occurred())
|
return NULL;
|
||||||
PyErr_SetString(PyExc_SystemError,
|
Py_INCREF(d);
|
||||||
"vars(): no locals!?");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
Py_INCREF(d);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
_Py_IDENTIFIER(__dict__);
|
_Py_IDENTIFIER(__dict__);
|
||||||
|
|
|
@ -2472,7 +2472,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
|
||||||
TARGET(IMPORT_STAR) {
|
TARGET(IMPORT_STAR) {
|
||||||
PyObject *from = POP(), *locals;
|
PyObject *from = POP(), *locals;
|
||||||
int err;
|
int err;
|
||||||
PyFrame_FastToLocals(f);
|
if (PyFrame_FastToLocalsWithError(f) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
locals = f->f_locals;
|
locals = f->f_locals;
|
||||||
if (locals == NULL) {
|
if (locals == NULL) {
|
||||||
PyErr_SetString(PyExc_SystemError,
|
PyErr_SetString(PyExc_SystemError,
|
||||||
|
@ -4005,9 +4007,15 @@ PyObject *
|
||||||
PyEval_GetLocals(void)
|
PyEval_GetLocals(void)
|
||||||
{
|
{
|
||||||
PyFrameObject *current_frame = PyEval_GetFrame();
|
PyFrameObject *current_frame = PyEval_GetFrame();
|
||||||
if (current_frame == NULL)
|
if (current_frame == NULL) {
|
||||||
|
PyErr_SetString(PyExc_SystemError, "frame does not exist");
|
||||||
return NULL;
|
return NULL;
|
||||||
PyFrame_FastToLocals(current_frame);
|
}
|
||||||
|
|
||||||
|
if (PyFrame_FastToLocalsWithError(current_frame) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
assert(current_frame->f_locals != NULL);
|
||||||
return current_frame->f_locals;
|
return current_frame->f_locals;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4017,8 +4025,9 @@ PyEval_GetGlobals(void)
|
||||||
PyFrameObject *current_frame = PyEval_GetFrame();
|
PyFrameObject *current_frame = PyEval_GetFrame();
|
||||||
if (current_frame == NULL)
|
if (current_frame == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
else
|
|
||||||
return current_frame->f_globals;
|
assert(current_frame->f_globals != NULL);
|
||||||
|
return current_frame->f_globals;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyFrameObject *
|
PyFrameObject *
|
||||||
|
|
|
@ -332,12 +332,16 @@ static PyObject *
|
||||||
call_trampoline(PyThreadState *tstate, PyObject* callback,
|
call_trampoline(PyThreadState *tstate, PyObject* callback,
|
||||||
PyFrameObject *frame, int what, PyObject *arg)
|
PyFrameObject *frame, int what, PyObject *arg)
|
||||||
{
|
{
|
||||||
PyObject *args = PyTuple_New(3);
|
PyObject *args;
|
||||||
PyObject *whatstr;
|
PyObject *whatstr;
|
||||||
PyObject *result;
|
PyObject *result;
|
||||||
|
|
||||||
|
args = PyTuple_New(3);
|
||||||
if (args == NULL)
|
if (args == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
if (PyFrame_FastToLocalsWithError(frame) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
Py_INCREF(frame);
|
Py_INCREF(frame);
|
||||||
whatstr = whatstrings[what];
|
whatstr = whatstrings[what];
|
||||||
Py_INCREF(whatstr);
|
Py_INCREF(whatstr);
|
||||||
|
@ -349,7 +353,6 @@ call_trampoline(PyThreadState *tstate, PyObject* callback,
|
||||||
PyTuple_SET_ITEM(args, 2, arg);
|
PyTuple_SET_ITEM(args, 2, arg);
|
||||||
|
|
||||||
/* call the Python-level function */
|
/* call the Python-level function */
|
||||||
PyFrame_FastToLocals(frame);
|
|
||||||
result = PyEval_CallObject(callback, args);
|
result = PyEval_CallObject(callback, args);
|
||||||
PyFrame_LocalsToFast(frame, 1);
|
PyFrame_LocalsToFast(frame, 1);
|
||||||
if (result == NULL)
|
if (result == NULL)
|
||||||
|
|
Loading…
Reference in New Issue