Commit 415e7ea3 authored by Mark Florisson's avatar Mark Florisson

Ensure 'cy locals' and 'cy exec' don't use uninitialized local variables...

Ensure 'cy locals' and 'cy exec' don't use uninitialized local variables (which fixes a lot of 'cy exec' core dumps! :)
parent 814c6376
......@@ -1606,13 +1606,22 @@ class DebugTransform(CythonTransform):
cname = entry.cname
# if entry.type.is_extension_type:
# cname = entry.type.typeptr_cname
if not entry.pos:
# this happens for variables that are not in the user's code,
# e.g. for the global __builtins__, __doc__, etc. We can just
# set the lineno to 0 for those.
lineno = '0'
else:
lineno = str(entry.pos[1])
attrs = dict(
name=entry.name,
cname=cname,
qualified_name=entry.qualified_name,
type=vartype)
type=vartype,
lineno=lineno)
self.tb.start('LocalVar', attrs)
self.tb.end('LocalVar')
......@@ -159,11 +159,12 @@ class CythonModule(object):
class CythonVariable(object):
def __init__(self, name, cname, qualified_name, type):
def __init__(self, name, cname, qualified_name, type, lineno):
self.name = name
self.cname = cname
self.qualified_name = qualified_name
self.type = type
self.lineno = int(lineno)
class CythonFunction(CythonVariable):
def __init__(self,
......@@ -177,10 +178,10 @@ class CythonFunction(CythonVariable):
super(CythonFunction, self).__init__(name,
cname,
qualified_name,
type)
type,
lineno)
self.module = module
self.pf_cname = pf_cname
self.lineno = int(lineno)
self.locals = {}
self.arguments = []
self.step_into_functions = set()
......@@ -387,6 +388,10 @@ class CythonBase(object):
print '%s%-*s = %s%s' % (prefix, max_name_length, name, typename,
value)
def is_initialized(self, cython_func, local_name):
cur_lineno = self.get_cython_lineno()
return (local_name in cython_func.arguments or
cur_lineno > cython_func.locals[local_name].lineno)
class SourceFileDescriptor(object):
def __init__(self, filename, lexer, formatter=None):
......@@ -1073,12 +1078,8 @@ class CyLocals(CythonCommand):
completer_class = gdb.COMPLETE_NONE
def _print_if_initialized(self, cyvar, max_name_length, prefix=''):
try:
if self.is_initialized(self.get_cython_function(), cyvar.name):
value = gdb.parse_and_eval(cyvar.cname)
except RuntimeError:
# variable not initialized yet
pass
else:
self.print_gdb_value(cyvar.name, value, max_name_length, prefix)
@dispatch_on_frame(c_command='info locals', python_command='py-locals')
......@@ -1134,20 +1135,12 @@ class CyExec(CythonCommand, libpython.PyExec):
def _fill_locals_dict(self, executor, local_dict_pointer):
"Fill a remotely allocated dict with values from the Cython C stack"
cython_func = self.get_cython_function()
current_lineno = self.get_cython_lineno()
for name, cyvar in cython_func.locals.iteritems():
if cyvar.type == PythonObject:
# skip unitialized Cython variables
try:
val = gdb.parse_and_eval(cyvar.cname)
except RuntimeError:
continue
else:
# Fortunately, Cython initializes all local (automatic)
# variables to NULL
if libpython.pointervalue(val) == 0:
continue
if (cyvar.type == PythonObject and
self.is_initialized(cython_func, name)):
pystringp = executor.alloc_pystring(name)
code = '''
PyDict_SetItem(
......@@ -1155,13 +1148,14 @@ class CyExec(CythonCommand, libpython.PyExec):
(PyObject *) %d,
(PyObject *) %s)
''' % (local_dict_pointer, pystringp, cyvar.cname)
# PyDict_SetItem doesn't steal our reference
executor.decref(pystringp)
if gdb.parse_and_eval(code) < 0:
gdb.parse_and_eval('PyErr_Print()')
raise gdb.GdbError("Unable to execute Python code.")
try:
if gdb.parse_and_eval(code) < 0:
gdb.parse_and_eval('PyErr_Print()')
raise gdb.GdbError("Unable to execute Python code.")
finally:
# PyDict_SetItem doesn't steal our reference
executor.decref(pystringp)
def _find_first_cython_or_python_frame(self):
frame = gdb.selected_frame()
......
......@@ -1929,7 +1929,7 @@ class PythonCodeExecutor(object):
pointer = pointervalue(chunk)
if pointer == 0:
err("No memory could be allocated in the inferior.")
raise gdb.GdbError("No memory could be allocated in the inferior.")
return pointer
......@@ -1950,7 +1950,7 @@ class PythonCodeExecutor(object):
pointer = pointervalue(result)
if pointer == 0:
err("Unable to allocate Python string in "
raise gdb.GdbError("Unable to allocate Python string in "
"the inferior.")
return pointer
......@@ -1958,6 +1958,10 @@ class PythonCodeExecutor(object):
def free(self, pointer):
gdb.parse_and_eval("free((void *) %d)" % pointer)
def incref(self, pointer):
"Increment the reference count of a Python object in the inferior."
gdb.parse_and_eval('Py_IncRef((PyObject *) %d)' % pointer)
def decref(self, pointer):
"Decrement the reference count of a Python object in the inferior."
# Py_DecRef is like Py_XDECREF, but a function. So we don't have
......@@ -1975,7 +1979,7 @@ class PythonCodeExecutor(object):
leave the debuggee in an unsafe state or terminate it alltogether.
"""
if '\0' in code:
err("String contains NUL byte.")
raise gdb.GdbError("String contains NUL byte.")
code += '\0'
......
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