(original) (raw)

changeset: 86715:4ef4578db38a user: Victor Stinner victor.stinner@gmail.com date: Tue Oct 29 01:19:37 2013 +0100 files: Include/frameobject.h Misc/NEWS Objects/frameobject.c Objects/object.c Python/bltinmodule.c Python/ceval.c Python/sysmodule.c description: 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. diff -r 6b86eb127030 -r 4ef4578db38a Include/frameobject.h --- a/Include/frameobject.h Tue Oct 29 00:59:44 2013 +0100 +++ b/Include/frameobject.h Tue Oct 29 01:19:37 2013 +0100 @@ -78,6 +78,8 @@ /* 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); diff -r 6b86eb127030 -r 4ef4578db38a Misc/NEWS --- a/Misc/NEWS Tue Oct 29 00:59:44 2013 +0100 +++ b/Misc/NEWS Tue Oct 29 01:19:37 2013 +0100 @@ -10,6 +10,10 @@ 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 diff -r 6b86eb127030 -r 4ef4578db38a Objects/frameobject.c --- a/Objects/frameobject.c Tue Oct 29 00:59:44 2013 +0100 +++ b/Objects/frameobject.c Tue Oct 29 01:19:37 2013 +0100 @@ -21,7 +21,8 @@ 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 @@ 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 @@ 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 @@ } } -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 @@ 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 diff -r 6b86eb127030 -r 4ef4578db38a Objects/object.c --- a/Objects/object.c Tue Oct 29 00:59:44 2013 +0100 +++ b/Objects/object.c Tue Oct 29 01:19:37 2013 +0100 @@ -1407,12 +1407,11 @@ _dir_locals(void) { PyObject *names; - PyObject *locals = PyEval_GetLocals(); + PyObject *locals; - if (locals == NULL) { - PyErr_SetString(PyExc_SystemError, "frame does not exist"); + locals = PyEval_GetLocals(); + if (locals == NULL) return NULL; - } names = PyMapping_Keys(locals); if (!names) diff -r 6b86eb127030 -r 4ef4578db38a Python/bltinmodule.c --- a/Python/bltinmodule.c Tue Oct 29 00:59:44 2013 +0100 +++ b/Python/bltinmodule.c Tue Oct 29 01:19:37 2013 +0100 @@ -755,8 +755,11 @@ } if (globals == Py_None) { globals = PyEval_GetGlobals(); - if (locals == Py_None) + if (locals == Py_None) { locals = PyEval_GetLocals(); + if (locals == NULL) + return NULL; + } } else if (locals == Py_None) locals = globals; @@ -820,6 +823,8 @@ globals = PyEval_GetGlobals(); if (locals == Py_None) { locals = PyEval_GetLocals(); + if (locals == NULL) + return NULL; } if (!globals || !locals) { PyErr_SetString(PyExc_SystemError, @@ -1926,13 +1931,9 @@ return NULL; if (v == NULL) { d = PyEval_GetLocals(); - if (d == NULL) { - if (!PyErr_Occurred()) - PyErr_SetString(PyExc_SystemError, - "vars(): no locals!?"); - } - else - Py_INCREF(d); + if (d == NULL) + return NULL; + Py_INCREF(d); } else { _Py_IDENTIFIER(__dict__); diff -r 6b86eb127030 -r 4ef4578db38a Python/ceval.c --- a/Python/ceval.c Tue Oct 29 00:59:44 2013 +0100 +++ b/Python/ceval.c Tue Oct 29 01:19:37 2013 +0100 @@ -2472,7 +2472,9 @@ TARGET(IMPORT_STAR) { PyObject *from = POP(), *locals; int err; - PyFrame_FastToLocals(f); + if (PyFrame_FastToLocalsWithError(f) < 0) + goto error; + locals = f->f_locals; if (locals == NULL) { PyErr_SetString(PyExc_SystemError, @@ -4005,9 +4007,15 @@ PyEval_GetLocals(void) { PyFrameObject *current_frame = PyEval_GetFrame(); - if (current_frame == NULL) + if (current_frame == NULL) { + PyErr_SetString(PyExc_SystemError, "frame does not exist"); 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; } @@ -4017,8 +4025,9 @@ PyFrameObject *current_frame = PyEval_GetFrame(); if (current_frame == NULL) return NULL; - else - return current_frame->f_globals; + + assert(current_frame->f_globals != NULL); + return current_frame->f_globals; } PyFrameObject * diff -r 6b86eb127030 -r 4ef4578db38a Python/sysmodule.c --- a/Python/sysmodule.c Tue Oct 29 00:59:44 2013 +0100 +++ b/Python/sysmodule.c Tue Oct 29 01:19:37 2013 +0100 @@ -332,12 +332,16 @@ call_trampoline(PyThreadState *tstate, PyObject* callback, PyFrameObject *frame, int what, PyObject *arg) { - PyObject *args = PyTuple_New(3); + PyObject *args; PyObject *whatstr; PyObject *result; + args = PyTuple_New(3); if (args == NULL) return NULL; + if (PyFrame_FastToLocalsWithError(frame) < 0) + return NULL; + Py_INCREF(frame); whatstr = whatstrings[what]; Py_INCREF(whatstr); @@ -349,7 +353,6 @@ PyTuple_SET_ITEM(args, 2, arg); /* call the Python-level function */ - PyFrame_FastToLocals(frame); result = PyEval_CallObject(callback, args); PyFrame_LocalsToFast(frame, 1); if (result == NULL) /victor.stinner@gmail.com