[pypy-commit] pypy py3.5: merge default into py3.5

mattip pypy.commits at gmail.com
Sun Apr 15 02:00:49 EDT 2018


Author: Matti Picus <matti.picus at gmail.com>
Branch: py3.5
Changeset: r94333:599b7470b778
Date: 2018-04-15 08:48 +0300
http://bitbucket.org/pypy/pypy/changeset/599b7470b778/

Log:	merge default into py3.5

diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -6,3 +6,7 @@
 .. startrev: f22145c34985
 
 
+.. branch: issue2752
+
+Fix a rare GC bug that was introduced more than one year ago, but was
+not diagnosed before issue #2752.
diff --git a/rpython/memory/gc/incminimark.py b/rpython/memory/gc/incminimark.py
--- a/rpython/memory/gc/incminimark.py
+++ b/rpython/memory/gc/incminimark.py
@@ -731,14 +731,16 @@
 
     def move_out_of_nursery(self, obj):
         # called twice, it should return the same shadow object,
-        # and not creating another shadow object
-        if self.header(obj).tid & GCFLAG_HAS_SHADOW:
-            shadow = self.nursery_objects_shadows.get(obj)
-            ll_assert(shadow != llmemory.NULL,
-                      "GCFLAG_HAS_SHADOW but no shadow found")
-            return shadow
-
-        return self._allocate_shadow(obj, copy=True)
+        # and not creating another shadow object.  As a safety feature,
+        # when called on a non-nursery object, do nothing.
+        if not self.is_in_nursery(obj):
+            return obj
+        shadow = self._find_shadow(obj)
+        if (self.header(obj).tid & GCFLAG_SHADOW_INITIALIZED) == 0:
+            self.header(obj).tid |= GCFLAG_SHADOW_INITIALIZED
+            totalsize = self.get_size(obj)
+            llmemory.raw_memcopy(obj, shadow, totalsize)
+        return shadow
 
     def collect(self, gen=2):
         """Do a minor (gen=0), start a major (gen=1), or do a full
@@ -2074,13 +2076,12 @@
             ll_assert(newobj != llmemory.NULL, "GCFLAG_HAS_SHADOW but no shadow found")
             newhdr = newobj - size_gc_header
             #
-            # Remove the flag GCFLAG_HAS_SHADOW, so that it doesn't get
-            # copied to the shadow itself.
-            self.header(obj).tid &= ~GCFLAG_HAS_SHADOW
+            # The flags GCFLAG_HAS_SHADOW and GCFLAG_SHADOW_INITIALIZED
+            # have no meaning in non-nursery objects.  We don't need to
+            # remove them explicitly here before doing the copy.
             tid = self.header(obj).tid
             if (tid & GCFLAG_SHADOW_INITIALIZED) != 0:
                 copy = False
-                self.header(obj).tid &= ~GCFLAG_SHADOW_INITIALIZED
             #
             totalsize = size_gc_header + self.get_size(obj)
             self.nursery_surviving_size += raw_malloc_usage(totalsize)
@@ -2644,8 +2645,7 @@
     # ----------
     # id() and identityhash() support
 
-    @specialize.arg(2)
-    def _allocate_shadow(self, obj, copy=False):
+    def _allocate_shadow(self, obj):
         size_gc_header = self.gcheaderbuilder.size_gc_header
         size = self.get_size(obj)
         shadowhdr = self._malloc_out_of_nursery(size_gc_header +
@@ -2667,12 +2667,6 @@
         #
         self.header(obj).tid |= GCFLAG_HAS_SHADOW
         self.nursery_objects_shadows.setitem(obj, shadow)
-
-        if copy:
-            self.header(obj).tid |= GCFLAG_SHADOW_INITIALIZED
-            totalsize = size_gc_header + self.get_size(obj)
-            llmemory.raw_memcopy(obj - size_gc_header, shadow, totalsize)
-
         return shadow
 
     def _find_shadow(self, obj):
diff --git a/rpython/memory/gc/test/test_direct.py b/rpython/memory/gc/test/test_direct.py
--- a/rpython/memory/gc/test/test_direct.py
+++ b/rpython/memory/gc/test/test_direct.py
@@ -671,6 +671,25 @@
         self.gc.debug_gc_step_until(incminimark.STATE_SCANNING)
         assert self.stackroots[1].x == 13
 
+    def test_move_out_of_nursery(self):
+        obj0 = self.malloc(S)
+        obj0.x = 123
+        adr1 = self.gc.move_out_of_nursery(llmemory.cast_ptr_to_adr(obj0))
+        obj1 = llmemory.cast_adr_to_ptr(adr1, lltype.Ptr(S))
+        assert obj1.x == 123
+        #
+        import pytest
+        obj2 = self.malloc(S)
+        obj2.x = 456
+        adr3 = self.gc._find_shadow(llmemory.cast_ptr_to_adr(obj2))
+        obj3 = llmemory.cast_adr_to_ptr(adr3, lltype.Ptr(S))
+        with pytest.raises(lltype.UninitializedMemoryAccess):
+            obj3.x     # the shadow is not populated yet
+        adr4 = self.gc.move_out_of_nursery(llmemory.cast_ptr_to_adr(obj2))
+        assert adr4 == adr3
+        assert obj3.x == 456     # it is populated now
+
+
 class TestIncrementalMiniMarkGCFull(DirectGCTest):
     from rpython.memory.gc.incminimark import IncrementalMiniMarkGC as GCClass
     def test_malloc_fixedsize_no_cleanup(self):


More information about the pypy-commit mailing list