Commit 6302b6bc authored by Stefan Behnel's avatar Stefan Behnel

Better fix for #1836: set frame flags to make CPython create a new dict for...

Better fix for #1836: set frame flags to make CPython create a new dict for "frame.f_locals" at need.
parent 15c065c4
...@@ -9249,7 +9249,9 @@ class CodeObjectNode(ExprNode): ...@@ -9249,7 +9249,9 @@ class CodeObjectNode(ExprNode):
file_path = StringEncoding.bytes_literal(func.pos[0].get_filenametable_entry().encode('utf8'), 'utf8') file_path = StringEncoding.bytes_literal(func.pos[0].get_filenametable_entry().encode('utf8'), 'utf8')
file_path_const = code.get_py_string_const(file_path, identifier=False, is_str=True) file_path_const = code.get_py_string_const(file_path, identifier=False, is_str=True)
flags = [] # This combination makes CPython create a new dict for "frame.f_locals" (see GH #1836).
flags = ['CO_OPTIMIZED', 'CO_NEWLOCALS']
if self.def_node.star_arg: if self.def_node.star_arg:
flags.append('CO_VARARGS') flags.append('CO_VARARGS')
if self.def_node.starstar_arg: if self.def_node.starstar_arg:
......
...@@ -252,7 +252,7 @@ static int __Pyx_TraceSetupAndCall(PyCodeObject** code, ...@@ -252,7 +252,7 @@ static int __Pyx_TraceSetupAndCall(PyCodeObject** code,
tstate, /*PyThreadState *tstate*/ tstate, /*PyThreadState *tstate*/
*code, /*PyCodeObject *code*/ *code, /*PyCodeObject *code*/
$moddict_cname, /*PyObject *globals*/ $moddict_cname, /*PyObject *globals*/
PyDict_New() /*PyObject *locals*/ 0 /*PyObject *locals*/
); );
if (*frame == NULL) return 0; if (*frame == NULL) return 0;
if (CYTHON_TRACE && (*frame)->f_trace == NULL) { if (CYTHON_TRACE && (*frame)->f_trace == NULL) {
...@@ -311,7 +311,8 @@ static PyCodeObject *__Pyx_createFrameCodeObject(const char *funcname, const cha ...@@ -311,7 +311,8 @@ static PyCodeObject *__Pyx_createFrameCodeObject(const char *funcname, const cha
#endif #endif
0, /*int nlocals,*/ 0, /*int nlocals,*/
0, /*int stacksize,*/ 0, /*int stacksize,*/
0, /*int flags,*/ // make CPython use a fresh dict for "f_locals" at need (see GH #1836)
CO_OPTIMIZED | CO_NEWLOCALS, /*int flags,*/
$empty_bytes, /*PyObject *code,*/ $empty_bytes, /*PyObject *code,*/
$empty_tuple, /*PyObject *consts,*/ $empty_tuple, /*PyObject *consts,*/
$empty_tuple, /*PyObject *names,*/ $empty_tuple, /*PyObject *names,*/
......
...@@ -58,9 +58,23 @@ cdef int trace_trampoline(PyObject* _traceobj, PyFrameObject* _frame, int what, ...@@ -58,9 +58,23 @@ cdef int trace_trampoline(PyObject* _traceobj, PyFrameObject* _frame, int what,
def _create_trace_func(trace): def _create_trace_func(trace):
local_names = {}
def _trace_func(frame, event, arg): def _trace_func(frame, event, arg):
trace.append((map_trace_types(event), frame.f_lineno - trace.append((map_trace_types(event), frame.f_lineno - frame.f_code.co_firstlineno))
frame.f_code.co_firstlineno))
lnames = frame.f_code.co_varnames
if frame.f_code.co_name in local_names:
assert lnames == local_names[frame.f_code.co_name]
else:
local_names[frame.f_code.co_name] = lnames
# Currently, the locals dict is empty for Cython code, but not for Python code.
if frame.f_code.co_name.startswith('py_'):
# Change this when we start providing proper access to locals.
assert frame.f_locals
else:
assert not frame.f_locals
return _trace_func return _trace_func
return _trace_func return _trace_func
...@@ -232,3 +246,14 @@ def disable_trace(func, *args): ...@@ -232,3 +246,14 @@ def disable_trace(func, *args):
finally: finally:
PyEval_SetTrace(NULL, None) PyEval_SetTrace(NULL, None)
return trace return trace
def global_name(global_name):
"""
>>> global_name(123)
444
>>> global_name(111)
432
"""
# See GH #1836: accessing "frame.f_locals" deletes locals from globals dict.
return global_name + 321
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