summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Behnel <stefan_ml@behnel.de>2014-11-28 15:46:31 +0100
committerStefan Behnel <stefan_ml@behnel.de>2014-11-28 15:46:31 +0100
commit31d5d476b5a9363badd5bcb45aefebaf27b4c5a6 (patch)
tree9d40a99a154a6a17d36ab97ec73ba92086e9cf15
parentea071f257199ec69beb28d9c691344b958a9b31f (diff)
downloadcython-31d5d476b5a9363badd5bcb45aefebaf27b4c5a6.tar.gz
fix temp leak and crash when assigning a C value to both a Python and C target in a cascaded assignment
-rw-r--r--Cython/Compiler/Nodes.py25
-rw-r--r--tests/run/cascaded_typed_assignments_T466.pyx15
2 files changed, 32 insertions, 8 deletions
diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py
index 81c5bf50d..f8215cb61 100644
--- a/Cython/Compiler/Nodes.py
+++ b/Cython/Compiler/Nodes.py
@@ -4788,10 +4788,11 @@ class CascadedAssignmentNode(AssignmentNode):
#
# Used internally:
#
- # coerced_rhs_list [ExprNode] RHS coerced to type of each LHS
+ # coerced_values [ExprNode] RHS coerced to all distinct LHS types
+ # cloned_values [ExprNode] cloned RHS value for each LHS
- child_attrs = ["lhs_list", "rhs", "coerced_values", "coerced_rhs_list"]
- coerced_rhs_list = None
+ child_attrs = ["lhs_list", "rhs", "coerced_values", "cloned_values"]
+ cloned_values = None
coerced_values = None
def analyse_declarations(self, env):
@@ -4801,6 +4802,7 @@ class CascadedAssignmentNode(AssignmentNode):
def analyse_types(self, env, use_temp=0):
from .ExprNodes import CloneNode, ProxyNode
+ # collect distinct types used on the LHS
lhs_types = set()
for lhs in self.lhs_list:
lhs.analyse_target_types(env)
@@ -4819,6 +4821,7 @@ class CascadedAssignmentNode(AssignmentNode):
rhs = rhs.coerce_to_simple(env)
self.rhs = ProxyNode(rhs) if rhs.is_temp else rhs
+ # clone RHS and coerce it to all distinct LHS types
self.coerced_values = []
coerced_values = {}
for lhs in self.lhs_list:
@@ -4827,22 +4830,28 @@ class CascadedAssignmentNode(AssignmentNode):
self.coerced_values.append(rhs)
coerced_values[lhs.type] = rhs
- self.coerced_rhs_list = []
+ # clone coerced values for all LHS assignments
+ self.cloned_values = []
for lhs in self.lhs_list:
rhs = coerced_values.get(lhs.type, self.rhs)
- self.coerced_rhs_list.append(CloneNode(rhs))
+ self.cloned_values.append(CloneNode(rhs))
return self
def generate_rhs_evaluation_code(self, code):
self.rhs.generate_evaluation_code(code)
def generate_assignment_code(self, code):
+ # prepare all coercions
for rhs in self.coerced_values:
rhs.generate_evaluation_code(code)
- for lhs, rhs in zip(self.lhs_list, self.coerced_rhs_list):
+ # assign clones to LHS
+ for lhs, rhs in zip(self.lhs_list, self.cloned_values):
rhs.generate_evaluation_code(code)
lhs.generate_assignment_code(rhs, code)
- # Assignment has disposed of the cloned RHS
+ # dispose of coerced values and original RHS
+ for rhs_value in self.coerced_values:
+ rhs_value.generate_disposal_code(code)
+ rhs_value.free_temps(code)
self.rhs.generate_disposal_code(code)
self.rhs.free_temps(code)
@@ -4852,7 +4861,7 @@ class CascadedAssignmentNode(AssignmentNode):
def annotate(self, code):
for rhs in self.coerced_values:
rhs.annotate(code)
- for lhs, rhs in zip(self.lhs_list, self.coerced_rhs_list):
+ for lhs, rhs in zip(self.lhs_list, self.cloned_values):
lhs.annotate(code)
rhs.annotate(code)
self.rhs.annotate(code)
diff --git a/tests/run/cascaded_typed_assignments_T466.pyx b/tests/run/cascaded_typed_assignments_T466.pyx
index 03cd5f516..eef9d5b7c 100644
--- a/tests/run/cascaded_typed_assignments_T466.pyx
+++ b/tests/run/cascaded_typed_assignments_T466.pyx
@@ -101,3 +101,18 @@ def assign_carray():
assert b[0] == 2
assert c[1] == 3
return a[0], b[0], c[1]
+
+
+def pyobject_from_cvalue(table, key):
+ """
+ >>> table = {'X':0, 'Y':1}
+ >>> pyobject_from_cvalue(table, 'Z')
+ 2
+ >>> pyobject_from_cvalue(table, 'X')
+ 0
+ """
+ cdef int num
+ num = table.get(key, -1)
+ if num < 0:
+ num = table[key] = len(table)
+ return num