[Python-checkins] python/dist/src/Lib/test test_gc.py,1.12.10.2,1.12.10.3
tim_one@users.sourceforge.net
tim_one@users.sourceforge.net
Tue, 08 Apr 2003 12:33:02 -0700
Update of /cvsroot/python/python/dist/src/Lib/test
In directory sc8-pr-cvs1:/tmp/cvs-serv21549/Lib/test
Modified Files:
Tag: release22-maint
test_gc.py
Log Message:
Backporting new gc-vs-__del__ tests. These pass, but are restricted
to old-style classes. New-style classes remain vulnerable in 2.2.
Index: test_gc.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/test/test_gc.py,v
retrieving revision 1.12.10.2
retrieving revision 1.12.10.3
diff -C2 -d -r1.12.10.2 -r1.12.10.3
*** test_gc.py 12 Jun 2002 14:41:50 -0000 1.12.10.2
--- test_gc.py 8 Apr 2003 19:32:53 -0000 1.12.10.3
***************
*** 207,210 ****
--- 207,261 ----
gc.disable()
+ class Boom:
+ def __getattr__(self, someattribute):
+ del self.attr
+ raise AttributeError
+
+ def test_boom():
+ a = Boom()
+ b = Boom()
+ a.attr = b
+ b.attr = a
+
+ gc.collect()
+ garbagelen = len(gc.garbage)
+ del a, b
+ # a<->b are in a trash cycle now. Collection will invoke Boom.__getattr__
+ # (to see whether a and b have __del__ methods), and __getattr__ deletes
+ # the internal "attr" attributes as a side effect. That causes the
+ # trash cycle to get reclaimed via refcounts falling to 0, thus mutating
+ # the trash graph as a side effect of merely asking whether __del__
+ # exists. This used to (before 2.3b1) crash Python. Now __getattr__
+ # isn't called.
+ expect(gc.collect(), 4, "boom")
+ expect(len(gc.garbage), garbagelen, "boom")
+
+ class Boom2:
+ def __init__(self):
+ self.x = 0
+
+ def __getattr__(self, someattribute):
+ self.x += 1
+ if self.x > 1:
+ del self.attr
+ raise AttributeError
+
+ def test_boom2():
+ a = Boom2()
+ b = Boom2()
+ a.attr = b
+ b.attr = a
+
+ gc.collect()
+ garbagelen = len(gc.garbage)
+ del a, b
+ # Much like test_boom(), except that __getattr__ doesn't break the
+ # cycle until the second time gc checks for __del__. As of 2.3b1,
+ # there isn't a second time, so this simply cleans up the trash cycle.
+ # We expect a, b, a.__dict__ and b.__dict__ (4 objects) to get reclaimed
+ # this way.
+ expect(gc.collect(), 4, "boom2")
+ expect(len(gc.garbage), garbagelen, "boom2")
+
def test_all():
gc.collect() # Delete 2nd generation garbage
***************
*** 223,226 ****
--- 274,279 ----
run_test("saveall", test_saveall)
run_test("trashcan", test_trashcan)
+ run_test("boom", test_boom)
+ run_test("boom2", test_boom2)
def test():