[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():