[pypy-svn] pypy default: Rework borrowed references, fixes a crash when an object is borrowed from two different containers

amauryfa commits-noreply at bitbucket.org
Tue Mar 15 19:20:50 CET 2011


Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: 
Changeset: r42675:d4aad1653f8b
Date: 2011-03-15 18:54 +0100
http://bitbucket.org/pypy/pypy/changeset/d4aad1653f8b/

Log:	Rework borrowed references, fixes a crash when an object is borrowed
	from two different containers

diff --git a/pypy/module/cpyext/pyobject.py b/pypy/module/cpyext/pyobject.py
--- a/pypy/module/cpyext/pyobject.py
+++ b/pypy/module/cpyext/pyobject.py
@@ -144,14 +144,11 @@
         # { w_container -> { w_containee -> None } }
         # the None entry manages references borrowed during a call to
         # generic_cpy_call()
-        self.borrowed_objects = {}
-        # { addr of containee -> None }
 
         # For tests
         self.non_heaptypes_w = []
 
     def _freeze_(self):
-        assert not self.borrowed_objects
         assert self.borrow_mapping == {None: {}}
         self.py_objects_r2w.clear() # is not valid anymore after translation
         return False
@@ -187,22 +184,19 @@
         """
         ref = make_ref(self.space, w_borrowed)
         obj_ptr = rffi.cast(ADDR, ref)
-        if obj_ptr not in self.borrowed_objects:
-            # borrowed_objects owns the reference
-            self.borrowed_objects[obj_ptr] = None
-        else:
-            Py_DecRef(self.space, ref) # already in borrowed list
 
         borrowees = self.borrow_mapping.setdefault(w_container, {})
-        borrowees[w_borrowed] = None
+        if w_borrowed in borrowees:
+            Py_DecRef(self.space, w_borrowed) # cancel incref from make_ref()
+        else:
+            borrowees[w_borrowed] = None
+
         return ref
 
     def reset_borrowed_references(self):
         "Used in tests"
-        while self.borrowed_objects:
-            addr, _ = self.borrowed_objects.popitem()
-            w_obj = self.py_objects_r2w[addr]
-            Py_DecRef(self.space, w_obj)
+        for w_container, w_borrowed in self.borrow_mapping.items():
+            Py_DecRef(self.space, w_borrowed)
         self.borrow_mapping = {None: {}}
 
     def delete_borrower(self, w_obj):
@@ -232,17 +226,10 @@
         ref = self.py_objects_w2r.get(w_obj, lltype.nullptr(PyObject.TO))
         if not ref:
             if DEBUG_REFCOUNT:
-                print >>sys.stderr, "Borrowed object is already gone:", \
-                      hex(containee)
+                print >>sys.stderr, "Borrowed object is already gone!"
             return
 
-        containee_ptr = rffi.cast(ADDR, ref)
-        try:
-            del self.borrowed_objects[containee_ptr]
-        except KeyError:
-            pass
-        else:
-            Py_DecRef(self.space, ref)
+        Py_DecRef(self.space, ref)
 
 class InvalidPointerException(Exception):
     pass
@@ -290,7 +277,6 @@
         if not replace:
             assert w_obj not in state.py_objects_w2r
         assert ptr not in state.py_objects_r2w
-        assert ptr not in state.borrowed_objects
     state.py_objects_w2r[w_obj] = py_obj
     if ptr: # init_typeobject() bootstraps with NULL references
         state.py_objects_r2w[ptr] = w_obj

diff --git a/pypy/module/cpyext/test/test_borrow.py b/pypy/module/cpyext/test/test_borrow.py
--- a/pypy/module/cpyext/test/test_borrow.py
+++ b/pypy/module/cpyext/test/test_borrow.py
@@ -39,7 +39,6 @@
         assert module.test_borrowing() # the test should not leak
 
     def test_borrow_destroy(self):
-        skip("FIXME")
         module = self.import_extension('foo', [
             ("test_borrow_destroy", "METH_NOARGS",
              """


More information about the Pypy-commit mailing list