Author: Armin Rigo <[email protected]>
Branch: gc-del-3
Changeset: r84186:6746f707cca8
Date: 2016-05-04 15:48 +0200
http://bitbucket.org/pypy/pypy/changeset/6746f707cca8/
Log: Check that finalizer_trigger() doesn't cause GIL-releasing
operations, like we check in the old-style non-light __del__().
diff --git a/rpython/rlib/rgc.py b/rpython/rlib/rgc.py
--- a/rpython/rlib/rgc.py
+++ b/rpython/rlib/rgc.py
@@ -501,6 +501,12 @@
return self.bookkeeper.immutablevalue(fq._fq_tag)
def specialize_call(self, hop):
+ from rpython.rtyper.rclass import InstanceRepr
+ translator = hop.rtyper.annotator.translator
+ fq = hop.args_s[0].const
+ graph = translator._graphof(fq.finalizer_trigger.im_func)
+ InstanceRepr.check_graph_of_del_does_not_call_too_much(hop.rtyper,
+ graph)
hop.exception_cannot_occur()
return hop.inputconst(lltype.Signed, hop.s_result.const)
diff --git a/rpython/rlib/test/test_rgc.py b/rpython/rlib/test/test_rgc.py
--- a/rpython/rlib/test/test_rgc.py
+++ b/rpython/rlib/test/test_rgc.py
@@ -1,4 +1,5 @@
from rpython.rtyper.test.test_llinterp import gengraph, interpret
+from rpython.rtyper.error import TyperError
from rpython.rtyper.lltypesystem import lltype, llmemory
from rpython.rlib import rgc # Force registration of gc.collect
import gc
@@ -265,7 +266,7 @@
self.x = x
class SimpleFQ(rgc.FinalizerQueue):
- base_class = T_Root
+ Class = T_Root
_triggered = 0
def finalizer_trigger(self):
self._triggered += 1
@@ -367,3 +368,21 @@
assert fq.next_dead() is None
assert deleted == {(1, 42): 1}
assert fq._triggered == 1
+
+ def test_finalizer_trigger_calls_too_much(self):
+ from rpython.rtyper.lltypesystem import lltype, rffi
+ external_func = rffi.llexternal("foo", [], lltype.Void)
+ # ^^^ with release_gil=True
+ class X(object):
+ pass
+ class FQ(rgc.FinalizerQueue):
+ Class = X
+ def finalizer_trigger(self):
+ external_func()
+ fq = FQ()
+ def f():
+ x = X()
+ fq.register_finalizer(x)
+
+ e = py.test.raises(TyperError, gengraph, f, [])
+ assert str(e.value).startswith('the RPython-level __del__() method in')
diff --git a/rpython/rtyper/rclass.py b/rpython/rtyper/rclass.py
--- a/rpython/rtyper/rclass.py
+++ b/rpython/rtyper/rclass.py
@@ -587,7 +587,8 @@
assert len(s_func.descriptions) == 1
funcdesc, = s_func.descriptions
graph = funcdesc.getuniquegraph()
- self.check_graph_of_del_does_not_call_too_much(graph)
+ self.check_graph_of_del_does_not_call_too_much(self.rtyper,
+ graph)
FUNCTYPE = FuncType([Ptr(source_repr.object_type)], Void)
destrptr = functionptr(FUNCTYPE, graph.name,
graph=graph,
@@ -859,7 +860,8 @@
def can_ll_be_null(self, s_value):
return s_value.can_be_none()
- def check_graph_of_del_does_not_call_too_much(self, graph):
+ @staticmethod
+ def check_graph_of_del_does_not_call_too_much(rtyper, graph):
# RPython-level __del__() methods should not do "too much".
# In the PyPy Python interpreter, they usually do simple things
# like file.__del__() closing the file descriptor; or if they
@@ -872,7 +874,7 @@
#
# XXX wrong complexity, but good enough because the set of
# reachable graphs should be small
- callgraph = self.rtyper.annotator.translator.callgraph.values()
+ callgraph = rtyper.annotator.translator.callgraph.values()
seen = {graph: None}
while True:
oldlength = len(seen)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit