[pypy-commit] pypy cpyext-avoid-roundtrip: _Py_NewReference did not initialize pypy_link: as such, reused tuples from the freelist could contain a wrong value. Test&fix

antocuni pypy.commits at gmail.com
Mon Oct 16 06:23:55 EDT 2017


Author: Antonio Cuni <anto.cuni at gmail.com>
Branch: cpyext-avoid-roundtrip
Changeset: r92775:0cd1a1fbbad9
Date: 2017-10-16 12:22 +0200
http://bitbucket.org/pypy/pypy/changeset/0cd1a1fbbad9/

Log:	_Py_NewReference did not initialize pypy_link: as such, reused
	tuples from the freelist could contain a wrong value. Test&fix

diff --git a/pypy/module/cpyext/include/object.h b/pypy/module/cpyext/include/object.h
--- a/pypy/module/cpyext/include/object.h
+++ b/pypy/module/cpyext/include/object.h
@@ -65,7 +65,10 @@
 #define Py_TYPE(ob)		(((PyObject*)(ob))->ob_type)
 #define Py_SIZE(ob)		(((PyVarObject*)(ob))->ob_size)
 
-#define _Py_NewReference(ob) (((PyObject *)(ob))->ob_refcnt = 1)
+#define _Py_NewReference(op)                                        \
+    ( ((PyObject *)(op))->ob_refcnt = 1,                            \
+      ((PyObject *)(op))->ob_pypy_link = 0 )
+
 #define _Py_ForgetReference(ob) /* nothing */
 
 #define Py_None (&_Py_NoneStruct)
diff --git a/pypy/module/cpyext/src/object.c b/pypy/module/cpyext/src/object.c
--- a/pypy/module/cpyext/src/object.c
+++ b/pypy/module/cpyext/src/object.c
@@ -17,7 +17,16 @@
     Py_XDECREF(o);
 }
 
-Py_ssize_t _pypy_rawrefcount_w_marker_deallocating;  /* set from pyobject.py */
+/* 
+ * The actual value of this variable will be the address of
+ * pyobject.w_marker_deallocating, and will be set by
+ * pyobject.write_w_marker_deallocating().
+ *
+ * The value set here is used only as a marker by tests (because during the
+ * tests we cannot call set_marker(), so we need to set a special value
+ * directly here)
+ */
+Py_ssize_t _pypy_rawrefcount_w_marker_deallocating = 0xDEADFFF;
 
 void
 _Py_Dealloc(PyObject *obj)
diff --git a/pypy/module/cpyext/test/test_tupleobject.py b/pypy/module/cpyext/test/test_tupleobject.py
--- a/pypy/module/cpyext/test/test_tupleobject.py
+++ b/pypy/module/cpyext/test/test_tupleobject.py
@@ -52,6 +52,31 @@
         py_b = as_pyobj(space, w_b)
         assert py_a != py_b
 
+    def test_PyTuple_New_initialize_pypy_link(self, space, api):
+        from rpython.rlib.rawrefcount import _collect
+        state = space.fromcache(State)
+        # see object.c:_pypy_rawrefcount_w_marker_deallocating
+        MARKER = 0xDEADFFF
+        #
+        # first: create a pytuple, attach a w_obj, decref the pytuple and let
+        # the GC to collect the w_obj: this way, c_ob_pypy_link is set to
+        # w_marker_deallocating
+        py_a = state.C.PyTuple_New(0)
+        assert py_a.c_ob_pypy_link == 0
+        w_a = from_ref(space, py_a)
+        assert py_a.c_ob_pypy_link != 0
+        decref(space, py_a)
+        w_a = None
+        _collect()
+        assert py_a.c_ob_pypy_link == MARKER
+        #
+        # second: create another tuple, which will reuse the same memory as
+        # before thanks to the freelist. Check that c_ob_pypy_link has been
+        # initialized to 0.
+        py_b = state.C.PyTuple_New(0)
+        assert py_b == py_a
+        assert py_b.c_ob_pypy_link == 0
+
     def test_tuple_resize(self, space, api):
         state = space.fromcache(State)
         w_42 = space.wrap(42)


More information about the pypy-commit mailing list