[pypy-commit] pypy default: rawrefcount fix: pyobjs waiting on the dead list of the GC should not
arigo
pypy.commits at gmail.com
Fri Mar 18 05:41:23 EDT 2016
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r83122:0173cdbbbacc
Date: 2016-03-18 09:46 +0000
http://bitbucket.org/pypy/pypy/changeset/0173cdbbbacc/
Log: rawrefcount fix: pyobjs waiting on the dead list of the GC should
not have refcnt == 0. See comment.
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -833,14 +833,14 @@
modulename = py.path.local(eci.libraries[-1])
def dealloc_trigger():
- from pypy.module.cpyext.pyobject import _Py_Dealloc
+ from pypy.module.cpyext.pyobject import decref
print 'dealloc_trigger...'
while True:
ob = rawrefcount.next_dead(PyObject)
if not ob:
break
print ob
- _Py_Dealloc(space, ob)
+ decref(space, ob)
print 'dealloc_trigger DONE'
return "RETRY"
rawrefcount.init(dealloc_trigger)
diff --git a/pypy/module/cpyext/state.py b/pypy/module/cpyext/state.py
--- a/pypy/module/cpyext/state.py
+++ b/pypy/module/cpyext/state.py
@@ -147,10 +147,10 @@
"""
def perform(self, executioncontext, frame):
- from pypy.module.cpyext.pyobject import PyObject, _Py_Dealloc
+ from pypy.module.cpyext.pyobject import PyObject, decref
while True:
py_obj = rawrefcount.next_dead(PyObject)
if not py_obj:
break
- _Py_Dealloc(self.space, py_obj)
+ decref(self.space, py_obj)
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
@@ -2929,10 +2929,19 @@
ll_assert(rc < int(REFCNT_FROM_PYPY_LIGHT * 0.99),
"refcount underflow from REFCNT_FROM_PYPY_LIGHT?")
rc -= REFCNT_FROM_PYPY
- self._pyobj(pyobject).ob_refcnt = rc
self._pyobj(pyobject).ob_pypy_link = 0
if rc == 0:
self.rrc_dealloc_pending.append(pyobject)
+ # an object with refcnt == 0 cannot stay around waiting
+ # for its deallocator to be called. Some code (lxml)
+ # expects that tp_dealloc is called immediately when
+ # the refcnt drops to 0. If it isn't, we get some
+ # uncleared raw pointer that can still be used to access
+ # the object; but (PyObject *)raw_pointer is then bogus
+ # because after a Py_INCREF()/Py_DECREF() on it, its
+ # tp_dealloc is also called!
+ rc = 1
+ self._pyobj(pyobject).ob_refcnt = rc
_rrc_free._always_inline_ = True
def rrc_major_collection_trace(self):
diff --git a/rpython/memory/gc/test/test_rawrefcount.py b/rpython/memory/gc/test/test_rawrefcount.py
--- a/rpython/memory/gc/test/test_rawrefcount.py
+++ b/rpython/memory/gc/test/test_rawrefcount.py
@@ -174,7 +174,7 @@
p1 = check_alive(0)
self._collect(major=True, expected_trigger=1)
py.test.raises(RuntimeError, "p1.x") # dead
- assert r1.ob_refcnt == 0
+ assert r1.ob_refcnt == 1 # in the pending list
assert r1.ob_pypy_link == 0
assert self.gc.rawrefcount_next_dead() == r1addr
assert self.gc.rawrefcount_next_dead() == llmemory.NULL
@@ -197,7 +197,7 @@
assert p1.x == 42
self._collect(major=True, expected_trigger=1)
py.test.raises(RuntimeError, "p1.x") # dead
- assert r1.ob_refcnt == 0
+ assert r1.ob_refcnt == 1
assert r1.ob_pypy_link == 0
assert self.gc.rawrefcount_next_dead() == r1addr
self.gc.check_no_more_rawrefcount_state()
@@ -214,7 +214,7 @@
else:
self._collect(major=False, expected_trigger=1)
py.test.raises(RuntimeError, "p1.x") # dead
- assert r1.ob_refcnt == 0
+ assert r1.ob_refcnt == 1
assert r1.ob_pypy_link == 0
assert self.gc.rawrefcount_next_dead() == r1addr
self.gc.check_no_more_rawrefcount_state()
@@ -252,7 +252,7 @@
self._collect(major=True, expected_trigger=1)
else:
self._collect(major=False, expected_trigger=1)
- assert r1.ob_refcnt == 0 # refcnt dropped to 0
+ assert r1.ob_refcnt == 1 # refcnt 1, in the pending list
assert r1.ob_pypy_link == 0 # detached
assert self.gc.rawrefcount_next_dead() == r1addr
self.gc.check_no_more_rawrefcount_state()
@@ -277,7 +277,7 @@
assert self.trigger == []
self._collect(major=True, expected_trigger=1)
py.test.raises(RuntimeError, "p1.x") # dead
- assert r1.ob_refcnt == 0
+ assert r1.ob_refcnt == 1
assert r1.ob_pypy_link == 0
assert self.gc.rawrefcount_next_dead() == r1addr
self.gc.check_no_more_rawrefcount_state()
diff --git a/rpython/rlib/rawrefcount.py b/rpython/rlib/rawrefcount.py
--- a/rpython/rlib/rawrefcount.py
+++ b/rpython/rlib/rawrefcount.py
@@ -136,6 +136,7 @@
ob.c_ob_refcnt -= REFCNT_FROM_PYPY
ob.c_ob_pypy_link = 0
if ob.c_ob_refcnt == 0:
+ ob.c_ob_refcnt = 1
_d_list.append(ob)
return None
diff --git a/rpython/rlib/test/test_rawrefcount.py b/rpython/rlib/test/test_rawrefcount.py
--- a/rpython/rlib/test/test_rawrefcount.py
+++ b/rpython/rlib/test/test_rawrefcount.py
@@ -116,7 +116,7 @@
assert rawrefcount.next_dead(PyObject) == lltype.nullptr(PyObjectS)
assert rawrefcount._o_list == []
assert wr_p() is None
- assert ob.c_ob_refcnt == 0
+ assert ob.c_ob_refcnt == 1 # from the pending list
assert ob.c_ob_pypy_link == 0
lltype.free(ob, flavor='raw')
@@ -173,7 +173,7 @@
assert rawrefcount._d_list == [ob]
assert rawrefcount._p_list == []
assert wr_p() is None
- assert ob.c_ob_refcnt == 0
+ assert ob.c_ob_refcnt == 1 # from _d_list
assert ob.c_ob_pypy_link == 0
lltype.free(ob, flavor='raw')
More information about the pypy-commit
mailing list