mirror of
https://github.com/python/cpython.git
synced 2025-10-10 00:43:41 +00:00
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
7 changed files with 87 additions and 46 deletions
|
@ -21,7 +21,8 @@ static PyMemberDef frame_memberlist[] = {
|
|||
static PyObject *
|
||||
frame_getlocals(PyFrameObject *f, void *closure)
|
||||
{
|
||||
PyFrame_FastToLocals(f);
|
||||
if (PyFrame_FastToLocalsWithError(f) < 0)
|
||||
return NULL;
|
||||
Py_INCREF(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
|
||||
and the value is extracted from the cell variable before being put
|
||||
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,
|
||||
int deref)
|
||||
{
|
||||
|
@ -794,14 +792,19 @@ map_to_dict(PyObject *map, Py_ssize_t nmap, PyObject *dict, PyObject **values,
|
|||
value = PyCell_GET(value);
|
||||
}
|
||||
if (value == NULL) {
|
||||
if (PyObject_DelItem(dict, key) != 0)
|
||||
PyErr_Clear();
|
||||
if (PyObject_DelItem(dict, key) != 0) {
|
||||
if (PyErr_ExceptionMatches(PyExc_KeyError))
|
||||
PyErr_Clear();
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (PyObject_SetItem(dict, key, value) != 0)
|
||||
PyErr_Clear();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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
|
||||
PyFrame_FastToLocals(PyFrameObject *f)
|
||||
int
|
||||
PyFrame_FastToLocalsWithError(PyFrameObject *f)
|
||||
{
|
||||
/* Merge fast locals into f->f_locals */
|
||||
PyObject *locals, *map;
|
||||
PyObject **fast;
|
||||
PyObject *error_type, *error_value, *error_traceback;
|
||||
PyCodeObject *co;
|
||||
Py_ssize_t j;
|
||||
Py_ssize_t ncells, nfreevars;
|
||||
if (f == NULL)
|
||||
return;
|
||||
|
||||
if (f == NULL) {
|
||||
PyErr_BadInternalCall();
|
||||
return -1;
|
||||
}
|
||||
locals = f->f_locals;
|
||||
if (locals == NULL) {
|
||||
locals = f->f_locals = PyDict_New();
|
||||
if (locals == NULL) {
|
||||
PyErr_Clear(); /* Can't report it :-( */
|
||||
return;
|
||||
}
|
||||
if (locals == NULL)
|
||||
return -1;
|
||||
}
|
||||
co = f->f_code;
|
||||
map = co->co_varnames;
|
||||
if (!PyTuple_Check(map))
|
||||
return;
|
||||
PyErr_Fetch(&error_type, &error_value, &error_traceback);
|
||||
if (!PyTuple_Check(map)) {
|
||||
PyErr_Format(PyExc_SystemError,
|
||||
"co_varnames must be a tuple, not %s",
|
||||
Py_TYPE(map)->tp_name);
|
||||
return -1;
|
||||
}
|
||||
fast = f->f_localsplus;
|
||||
j = PyTuple_GET_SIZE(map);
|
||||
if (j > co->co_nlocals)
|
||||
j = co->co_nlocals;
|
||||
if (co->co_nlocals)
|
||||
map_to_dict(map, j, locals, fast, 0);
|
||||
if (co->co_nlocals) {
|
||||
if (map_to_dict(map, j, locals, fast, 0) < 0)
|
||||
return -1;
|
||||
}
|
||||
ncells = PyTuple_GET_SIZE(co->co_cellvars);
|
||||
nfreevars = PyTuple_GET_SIZE(co->co_freevars);
|
||||
if (ncells || nfreevars) {
|
||||
map_to_dict(co->co_cellvars, ncells,
|
||||
locals, fast + co->co_nlocals, 1);
|
||||
if (map_to_dict(co->co_cellvars, ncells,
|
||||
locals, fast + co->co_nlocals, 1))
|
||||
return -1;
|
||||
|
||||
/* If the namespace is unoptimized, then one of the
|
||||
following cases applies:
|
||||
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.
|
||||
*/
|
||||
if (co->co_flags & CO_OPTIMIZED) {
|
||||
map_to_dict(co->co_freevars, nfreevars,
|
||||
locals, fast + co->co_nlocals + ncells, 1);
|
||||
if (map_to_dict(co->co_freevars, nfreevars,
|
||||
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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue