cpython: 4ef4578db38a (original) (raw)
Mercurial > cpython
changeset 86715:4ef4578db38a
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. [#18408]
Victor Stinner victor.stinner@gmail.com | |
---|---|
date | Tue, 29 Oct 2013 01:19:37 +0100 |
parents | 6b86eb127030 |
children | e1d51c42e5a1 |
files | Include/frameobject.h Misc/NEWS Objects/frameobject.c Objects/object.c Python/bltinmodule.c Python/ceval.c Python/sysmodule.c |
diffstat | 7 files changed, 87 insertions(+), 46 deletions(-)[+] [-] Include/frameobject.h 2 Misc/NEWS 4 Objects/frameobject.c 77 Objects/object.c 7 Python/bltinmodule.c 17 Python/ceval.c 19 Python/sysmodule.c 7 |
line wrap: on
line diff
--- a/Include/frameobject.h +++ b/Include/frameobject.h @@ -78,6 +78,8 @@ PyAPI_FUNC(PyObject **) PyFrame_ExtendSt /* Conversions between "fast locals" and locals in dictionary */ PyAPI_FUNC(void) PyFrame_LocalsToFast(PyFrameObject *, int); + +PyAPI_FUNC(int) PyFrame_FastToLocalsWithError(PyFrameObject *f); PyAPI_FUNC(void) PyFrame_FastToLocals(PyFrameObject *); PyAPI_FUNC(int) PyFrame_ClearFreeList(void);
--- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ Projected release date: 2013-11-24 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 #18603: Ensure that PyOS_mystricmp and PyOS_mystrnicmp are in the
--- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -21,7 +21,8 @@ static PyMemberDef frame_memberlist[] = static PyObject * frame_getlocals(PyFrameObject *f, void *closure) {
- if (PyFrame_FastToLocalsWithError(f) < 0)
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. -return NULL;[](#l3.9)
- 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 nm value = PyCell_GET(value); } if (value == NULL) {
if (PyObject_DelItem(dict, key) != 0)[](#l3.31)
PyErr_Clear();[](#l3.32)
if (PyObject_DelItem(dict, key) != 0) {[](#l3.33)
if (PyErr_ExceptionMatches(PyExc_KeyError))[](#l3.34)
PyErr_Clear();[](#l3.35)
else[](#l3.36)
return -1;[](#l3.37)
}[](#l3.38) }[](#l3.39) else {[](#l3.40) if (PyObject_SetItem(dict, key, value) != 0)[](#l3.41)
PyErr_Clear();[](#l3.42)
} /* Copy values from the "locals" dict into the fast locals. @@ -858,42 +861,49 @@ dict_to_map(PyObject *map, Py_ssize_t nm } } -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;[](#l3.67)
- if (f == NULL) {
PyErr_BadInternalCall();[](#l3.70)
return -1;[](#l3.71)
- } locals = f->f_locals; if (locals == NULL) { locals = f->f_locals = PyDict_New();
if (locals == NULL) {[](#l3.76)
PyErr_Clear(); /* Can't report it :-( */[](#l3.77)
return;[](#l3.78)
}[](#l3.79)
- if (!PyTuple_Check(map))
return;[](#l3.86)
- PyErr_Fetch(&error_type, &error_value, &error_traceback);
- if (!PyTuple_Check(map)) {
PyErr_Format(PyExc_SystemError,[](#l3.89)
"co_varnames must be a tuple, not %s",[](#l3.90)
Py_TYPE(map)->tp_name);[](#l3.91)
return -1;[](#l3.92)
- } fast = f->f_localsplus; j = PyTuple_GET_SIZE(map); if (j > co->co_nlocals) j = co->co_nlocals;
- if (co->co_nlocals) {
if (map_to_dict(map, j, locals, fast, 0) < 0)[](#l3.101)
return -1;[](#l3.102)
- } ncells = PyTuple_GET_SIZE(co->co_cellvars); nfreevars = PyTuple_GET_SIZE(co->co_freevars); if (ncells || nfreevars) {
map_to_dict(co->co_cellvars, ncells,[](#l3.107)
locals, fast + co->co_nlocals, 1);[](#l3.108)
if (map_to_dict(co->co_cellvars, ncells,[](#l3.109)
locals, fast + co->co_nlocals, 1))[](#l3.110)
return -1;[](#l3.111)
+ /* 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,[](#l3.120)
locals, fast + co->co_nlocals + ncells, 1);[](#l3.121)
if (map_to_dict(co->co_freevars, nfreevars,[](#l3.122)
locals, fast + co->co_nlocals + ncells, 1) < 0)[](#l3.123)
}return -1;[](#l3.124) }[](#l3.125)
+} + +void +PyFrame_FastToLocals(PyFrameObject *f) +{
--- a/Objects/object.c +++ b/Objects/object.c @@ -1407,12 +1407,11 @@ static PyObject * _dir_locals(void) { PyObject *names;
names = PyMapping_Keys(locals); if (!names)
--- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -755,8 +755,11 @@ builtin_eval(PyObject *self, PyObject *a } if (globals == Py_None) { globals = PyEval_GetGlobals();
if (locals == Py_None)[](#l5.7)
if (locals == Py_None) {[](#l5.8) locals = PyEval_GetLocals();[](#l5.9)
if (locals == NULL)[](#l5.10)
return NULL;[](#l5.11)
} else if (locals == Py_None) locals = globals;}[](#l5.12)
@@ -820,6 +823,8 @@ builtin_exec(PyObject *self, PyObject *a globals = PyEval_GetGlobals(); if (locals == Py_None) { locals = PyEval_GetLocals();
if (locals == NULL)[](#l5.20)
return NULL;[](#l5.21) }[](#l5.22) if (!globals || !locals) {[](#l5.23) PyErr_SetString(PyExc_SystemError,[](#l5.24)
@@ -1926,13 +1931,9 @@ builtin_vars(PyObject *self, PyObject *a return NULL; if (v == NULL) { d = PyEval_GetLocals();
if (d == NULL) {[](#l5.29)
if (!PyErr_Occurred())[](#l5.30)
PyErr_SetString(PyExc_SystemError,[](#l5.31)
"vars(): no locals!?");[](#l5.32)
}[](#l5.33)
else[](#l5.34)
Py_INCREF(d);[](#l5.35)
if (d == NULL)[](#l5.36)
return NULL;[](#l5.37)
} else { _Py_IDENTIFIER(dict);Py_INCREF(d);[](#l5.38)
--- a/Python/ceval.c +++ b/Python/ceval.c @@ -2472,7 +2472,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int TARGET(IMPORT_STAR) { PyObject *from = POP(), *locals; int err;
PyFrame_FastToLocals(f);[](#l6.7)
if (PyFrame_FastToLocalsWithError(f) < 0)[](#l6.8)
goto error;[](#l6.9)
+ locals = f->f_locals; if (locals == NULL) { PyErr_SetString(PyExc_SystemError, @@ -4005,9 +4007,15 @@ PyObject * PyEval_GetLocals(void) { PyFrameObject *current_frame = PyEval_GetFrame();
- if (current_frame == NULL) {
PyErr_SetString(PyExc_SystemError, "frame does not exist");[](#l6.20) return NULL;[](#l6.21)
@@ -4017,8 +4025,9 @@ PyEval_GetGlobals(void) PyFrameObject *current_frame = PyEval_GetFrame(); if (current_frame == NULL) return NULL;
--- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -332,12 +332,16 @@ static PyObject * call_trampoline(PyThreadState tstate, PyObject callback, PyFrameObject *frame, int what, PyObject *arg) {
- PyObject *args; PyObject *whatstr; PyObject *result;
- args = PyTuple_New(3); if (args == NULL) return NULL;
- if (PyFrame_FastToLocalsWithError(frame) < 0)
return NULL;[](#l7.16)
+ Py_INCREF(frame); whatstr = whatstrings[what]; Py_INCREF(whatstr); @@ -349,7 +353,6 @@ call_trampoline(PyThreadState tstate, P PyTuple_SET_ITEM(args, 2, arg); / call the Python-level function */