Commit 41bb43a7 authored by Victor Stinner's avatar Victor Stinner

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.
parent 28c63f7f
...@@ -78,6 +78,8 @@ PyAPI_FUNC(PyObject **) PyFrame_ExtendStack(PyFrameObject *, int, int); ...@@ -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 ...@@ -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[] = { ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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 * ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 * ...@@ -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) ...@@ -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 * ...@@ -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, ...@@ -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)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment