fix bug 633: make sure we own references to Python arguments passed into C functions
authorStefan Behnel <scoder@users.berlios.de>
Sun, 26 Dec 2010 21:34:22 +0000 (22:34 +0100)
committerStefan Behnel <scoder@users.berlios.de>
Sun, 26 Dec 2010 21:34:22 +0000 (22:34 +0100)
Cython/Compiler/ExprNodes.py
tests/run/owned_arg_refs.pyx [new file with mode: 0644]

index c0440641ae4794bfe38100bff6037528b47b5de8..8aead92cc4bc09ab06f32dc68cca9dbd5aa65641 100755 (executable)
@@ -2953,7 +2953,14 @@ class SimpleCallNode(CallNode):
         # Coerce arguments
         for i in range(min(max_nargs, actual_nargs)):
             formal_type = func_type.args[i].type
-            self.args[i] = self.args[i].coerce_to(formal_type, env)
+            arg = self.args[i].coerce_to(formal_type, env)
+            if arg.is_attribute or not arg.is_simple:
+                # we do not own the argument's reference, but we must
+                # make sure it cannot be collected before we return
+                # from the function, so we create an owned temp
+                # reference to it
+                arg = arg.coerce_to_temp(env)
+            self.args[i] = arg
         for i in range(max_nargs, actual_nargs):
             if self.args[i].type.is_pyobject:
                 error(self.args[i].pos,
diff --git a/tests/run/owned_arg_refs.pyx b/tests/run/owned_arg_refs.pyx
new file mode 100644 (file)
index 0000000..5bf84d7
--- /dev/null
@@ -0,0 +1,28 @@
+
+cdef class Owner:
+    cdef object x
+
+cdef call_me_with_owner(Owner owner, x):
+    owner.x = "def" # overwrite external reference
+    return x        # crashes if x is not owned by function or caller
+
+def test_ext_type_attr():
+    """
+    >>> test_ext_type_attr()
+    'abc5'
+    """
+    owner = Owner()
+    owner.x = ''.join("abc%d" % 5) # non-interned object
+    return call_me_with_owner(owner, owner.x)
+
+cdef call_me_with_list(list l, x):
+    l[:] = [(1,2), (3,4)] # overwrite external reference
+    return x              # crashes if x is not owned by function or caller
+
+def test_index():
+    """
+    >>> test_index()
+    [3, 4]
+    """
+    l = [[1,2],[3,4]]
+    return call_me_with_list(l, l[1])