From 7b49db410006992dd518370989123d1fe1afc0ea Mon Sep 17 00:00:00 2001 From: Dag Sverre Seljebotn Date: Thu, 27 Nov 2008 12:01:35 +0100 Subject: [PATCH] Introduced manage_ref parameter in funcstate.allocate_temp and used it to fix crash bug. --- Cython/Compiler/Buffer.py | 2 +- Cython/Compiler/Code.py | 28 +++++++++++++++++----------- Cython/Compiler/Nodes.py | 8 ++++---- Cython/Compiler/UtilNodes.py | 2 +- 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/Cython/Compiler/Buffer.py b/Cython/Compiler/Buffer.py index 9134f825..7ce70468 100644 --- a/Cython/Compiler/Buffer.py +++ b/Cython/Compiler/Buffer.py @@ -298,7 +298,7 @@ def put_assign_to_buffer(lhs_cname, rhs_cname, buffer_aux, buffer_type, # before raising the exception. A failure of reacquisition # will cause the reacquisition exception to be reported, one # can consider working around this later. - type, value, tb = [code.funcstate.allocate_temp(PyrexTypes.py_object_type) + type, value, tb = [code.funcstate.allocate_temp(PyrexTypes.py_object_type, manage_ref=False) for i in range(3)] code.putln('PyErr_Fetch(&%s, &%s, &%s);' % (type, value, tb)) code.putln('if (%s) {' % code.unlikely("%s == -1" % (getbuffer % lhs_cname))) diff --git a/Cython/Compiler/Code.py b/Cython/Compiler/Code.py index 075c6719..3841e608 100644 --- a/Cython/Compiler/Code.py +++ b/Cython/Compiler/Code.py @@ -40,7 +40,7 @@ class FunctionState(object): self.in_try_finally = 0 self.exc_vars = None - self.temps_allocated = [] # of (name, type) + self.temps_allocated = [] # of (name, type, manage_ref) self.temps_free = {} # type -> list of free vars self.temps_used_type = {} # name -> type self.temp_counter = 0 @@ -104,12 +104,17 @@ class FunctionState(object): def label_used(self, lbl): return lbl in self.labels_used - def allocate_temp(self, type): + def allocate_temp(self, type, manage_ref=True): """ Allocates a temporary (which may create a new one or get a previously allocated and released one of the same type). Type is simply registered and handed back, but will usually be a PyrexType. + If type.is_pyobject, manage_ref comes into play. If manage_ref is set to + True, the temp will be decref-ed on return statements and in exception + handling clauses. Otherwise the caller has to deal with any reference + counting of the variable. + A C string referring to the variable is returned. """ freelist = self.temps_free.get(type) @@ -120,7 +125,7 @@ class FunctionState(object): self.temp_counter += 1 result = "%s%d" % (Naming.codewriter_temp_prefix, self.temp_counter) if not result in self.names_taken: break - self.temps_allocated.append((result, type)) + self.temps_allocated.append((result, type, manage_ref)) self.temps_used_type[result] = type return result @@ -138,23 +143,24 @@ class FunctionState(object): freelist.append(name) def temps_in_use(self): - """Return a list of (cname,type) tuples of temp names and their type + """Return a list of (cname,type,manage_ref) tuples of temp names and their type that are currently in use. """ used = [] - for name, type in self.temps_allocated: + for name, type, manage_ref in self.temps_allocated: freelist = self.temps_free.get(type) if freelist is None or name not in freelist: - used.append((name, type)) + used.append((name, type, manage_ref)) return used - def py_temps_in_use(self): + def temps_holding_reference(self): """Return a list of (cname,type) tuples of temp names and their type - that are currently in use. This includes only Python object types. + that are currently in use. This includes only temps of a + Python object type which owns its reference. """ return [(name, type) - for name, type in self.temps_in_use() - if type.is_pyobject] + for name, type, manage_ref in self.temps_in_use() + if (type.is_pyobject and manage_ref)] class GlobalState(object): # filename_table {string : int} for finding filename table indexes @@ -674,7 +680,7 @@ class CCodeWriter(object): self.putln(";") def put_temp_declarations(self, func_context): - for name, type in func_context.temps_allocated: + for name, type, manage_ref in func_context.temps_allocated: decl = type.declaration_code(name) if type.is_pyobject: self.putln("%s = NULL;" % decl) diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index 3c634861..e7b168be 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -1063,8 +1063,8 @@ class FuncDefNode(StatNode, BlockNode): # cleanup temps the old way code.put_var_xdecrefs(lenv.temp_entries) # cleanup temps the new way - for cname, type in code.funcstate.temps_allocated: - if type.is_pyobject: + for cname, type, manage_ref in code.funcstate.temps_allocated: + if type.is_pyobject and manage_ref: code.put_xdecref(cname, type) # Clean up buffers -- this calls a Python function @@ -2369,7 +2369,7 @@ class PyClassDefNode(ClassDefNode): def as_cclass(self): """ - Return this node as if it were declared as an extension class" + Return this node as if it were declared as an extension class """ bases = self.classobj.bases.args if len(bases) == 0: @@ -3296,7 +3296,7 @@ class ReturnStatNode(StatNode): for entry in self.temps_in_use: code.put_var_decref_clear(entry) # free temps the new way - for cname, type in code.funcstate.py_temps_in_use(): + for cname, type in code.funcstate.temps_holding_reference(): code.put_decref_clear(cname, type) #code.putln( # "goto %s;" % diff --git a/Cython/Compiler/UtilNodes.py b/Cython/Compiler/UtilNodes.py index ec3727a9..7fcf6fda 100644 --- a/Cython/Compiler/UtilNodes.py +++ b/Cython/Compiler/UtilNodes.py @@ -79,7 +79,7 @@ class TempsBlockNode(Node): def generate_execution_code(self, code): for handle in self.temps: - handle.temp = code.funcstate.allocate_temp(handle.type) + handle.temp = code.funcstate.allocate_temp(handle.type, manage_ref=True) self.body.generate_execution_code(code) for handle in self.temps: if handle.needs_cleanup: -- 2.26.2