blob: 9abf285ba5d2a1eca86878807bcf96d2321fe865 [file] [log] [blame]
Collin Winterfef1dcf2007-04-06 20:00:05 +00001import unittest
2from test.test_support import verbose, run_unittest
Neil Schemenauer88c761a2001-07-12 13:25:53 +00003import sys
Jeremy Hyltonc5007aa2000-06-30 05:02:53 +00004import gc
Tim Petersead8b7a2004-10-30 23:09:22 +00005import weakref
Jeremy Hyltonc5007aa2000-06-30 05:02:53 +00006
Collin Winterfef1dcf2007-04-06 20:00:05 +00007### Support code
8###############################################################################
Neal Norwitz0d4c06e2007-04-25 06:30:05 +00009
Tim Petersead8b7a2004-10-30 23:09:22 +000010# Bug 1055820 has several tests of longstanding bugs involving weakrefs and
11# cyclic gc.
12
13# An instance of C1055820 has a self-loop, so becomes cyclic trash when
14# unreachable.
15class C1055820(object):
16 def __init__(self, i):
17 self.i = i
18 self.loop = self
19
20class GC_Detector(object):
21 # Create an instance I. Then gc hasn't happened again so long as
22 # I.gc_happened is false.
23
24 def __init__(self):
25 self.gc_happened = False
26
27 def it_happened(ignored):
28 self.gc_happened = True
29
30 # Create a piece of cyclic trash that triggers it_happened when
31 # gc collects it.
32 self.wr = weakref.ref(C1055820(666), it_happened)
33
Tim Petersead8b7a2004-10-30 23:09:22 +000034
Neal Norwitz0d4c06e2007-04-25 06:30:05 +000035### Tests
Collin Winterfef1dcf2007-04-06 20:00:05 +000036###############################################################################
Neal Norwitz0d4c06e2007-04-25 06:30:05 +000037
Collin Winterfef1dcf2007-04-06 20:00:05 +000038class GCTests(unittest.TestCase):
39 def test_list(self):
40 l = []
41 l.append(l)
42 gc.collect()
43 del l
44 self.assertEqual(gc.collect(), 1)
Tim Petersead8b7a2004-10-30 23:09:22 +000045
Collin Winterfef1dcf2007-04-06 20:00:05 +000046 def test_dict(self):
47 d = {}
48 d[1] = d
49 gc.collect()
50 del d
51 self.assertEqual(gc.collect(), 1)
Tim Petersead8b7a2004-10-30 23:09:22 +000052
Collin Winterfef1dcf2007-04-06 20:00:05 +000053 def test_tuple(self):
54 # since tuples are immutable we close the loop with a list
55 l = []
56 t = (l,)
57 l.append(t)
58 gc.collect()
59 del t
60 del l
61 self.assertEqual(gc.collect(), 2)
Tim Petersead8b7a2004-10-30 23:09:22 +000062
Collin Winterfef1dcf2007-04-06 20:00:05 +000063 def test_class(self):
64 class A:
65 pass
66 A.a = A
67 gc.collect()
68 del A
69 self.assertNotEqual(gc.collect(), 0)
Tim Petersead8b7a2004-10-30 23:09:22 +000070
Collin Winterfef1dcf2007-04-06 20:00:05 +000071 def test_newstyleclass(self):
72 class A(object):
73 pass
74 gc.collect()
75 del A
76 self.assertNotEqual(gc.collect(), 0)
Tim Petersead8b7a2004-10-30 23:09:22 +000077
Collin Winterfef1dcf2007-04-06 20:00:05 +000078 def test_instance(self):
79 class A:
80 pass
81 a = A()
82 a.a = a
83 gc.collect()
84 del a
85 self.assertNotEqual(gc.collect(), 0)
Tim Petersead8b7a2004-10-30 23:09:22 +000086
Collin Winterfef1dcf2007-04-06 20:00:05 +000087 def test_newinstance(self):
88 class A(object):
89 pass
90 a = A()
91 a.a = a
92 gc.collect()
93 del a
94 self.assertNotEqual(gc.collect(), 0)
95 class B(list):
96 pass
97 class C(B, A):
98 pass
99 a = C()
100 a.a = a
101 gc.collect()
102 del a
103 self.assertNotEqual(gc.collect(), 0)
104 del B, C
105 self.assertNotEqual(gc.collect(), 0)
106 A.a = A()
107 del A
108 self.assertNotEqual(gc.collect(), 0)
109 self.assertEqual(gc.collect(), 0)
Tim Petersead8b7a2004-10-30 23:09:22 +0000110
Collin Winterfef1dcf2007-04-06 20:00:05 +0000111 def test_method(self):
112 # Tricky: self.__init__ is a bound method, it references the instance.
113 class A:
114 def __init__(self):
115 self.init = self.__init__
116 a = A()
117 gc.collect()
118 del a
119 self.assertNotEqual(gc.collect(), 0)
Tim Petersead8b7a2004-10-30 23:09:22 +0000120
Collin Winterfef1dcf2007-04-06 20:00:05 +0000121 def test_finalizer(self):
122 # A() is uncollectable if it is part of a cycle, make sure it shows up
123 # in gc.garbage.
124 class A:
125 def __del__(self): pass
126 class B:
127 pass
128 a = A()
129 a.a = a
130 id_a = id(a)
131 b = B()
132 b.b = b
133 gc.collect()
134 del a
135 del b
136 self.assertNotEqual(gc.collect(), 0)
137 for obj in gc.garbage:
138 if id(obj) == id_a:
139 del obj.a
140 break
141 else:
142 self.fail("didn't find obj in garbage (finalizer)")
143 gc.garbage.remove(obj)
Tim Petersead8b7a2004-10-30 23:09:22 +0000144
Collin Winterfef1dcf2007-04-06 20:00:05 +0000145 def test_finalizer_newclass(self):
146 # A() is uncollectable if it is part of a cycle, make sure it shows up
147 # in gc.garbage.
148 class A(object):
149 def __del__(self): pass
150 class B(object):
151 pass
152 a = A()
153 a.a = a
154 id_a = id(a)
155 b = B()
156 b.b = b
157 gc.collect()
158 del a
159 del b
160 self.assertNotEqual(gc.collect(), 0)
161 for obj in gc.garbage:
162 if id(obj) == id_a:
163 del obj.a
164 break
165 else:
166 self.fail("didn't find obj in garbage (finalizer)")
167 gc.garbage.remove(obj)
Tim Petersead8b7a2004-10-30 23:09:22 +0000168
Collin Winterfef1dcf2007-04-06 20:00:05 +0000169 def test_function(self):
170 # Tricky: f -> d -> f, code should call d.clear() after the exec to
171 # break the cycle.
172 d = {}
173 exec("def f(): pass\n") in d
174 gc.collect()
175 del d
176 self.assertEqual(gc.collect(), 2)
Tim Petersead8b7a2004-10-30 23:09:22 +0000177
Collin Winterfef1dcf2007-04-06 20:00:05 +0000178 def test_frame(self):
179 def f():
180 frame = sys._getframe()
181 gc.collect()
182 f()
183 self.assertEqual(gc.collect(), 1)
Tim Petersead8b7a2004-10-30 23:09:22 +0000184
Collin Winterfef1dcf2007-04-06 20:00:05 +0000185 def test_saveall(self):
186 # Verify that cyclic garbage like lists show up in gc.garbage if the
187 # SAVEALL option is enabled.
Tim Petersead8b7a2004-10-30 23:09:22 +0000188
Collin Winterfef1dcf2007-04-06 20:00:05 +0000189 # First make sure we don't save away other stuff that just happens to
190 # be waiting for collection.
191 gc.collect()
192 # if this fails, someone else created immortal trash
193 self.assertEqual(gc.garbage, [])
Tim Petersead8b7a2004-10-30 23:09:22 +0000194
Collin Winterfef1dcf2007-04-06 20:00:05 +0000195 L = []
196 L.append(L)
197 id_L = id(L)
198
199 debug = gc.get_debug()
200 gc.set_debug(debug | gc.DEBUG_SAVEALL)
201 del L
202 gc.collect()
203 gc.set_debug(debug)
204
205 self.assertEqual(len(gc.garbage), 1)
206 obj = gc.garbage.pop()
207 self.assertEqual(id(obj), id_L)
208
209 def test_del(self):
210 # __del__ methods can trigger collection, make this to happen
211 thresholds = gc.get_threshold()
212 gc.enable()
213 gc.set_threshold(1)
214
215 class A:
216 def __del__(self):
217 dir(self)
218 a = A()
219 del a
220
221 gc.disable()
222 gc.set_threshold(*thresholds)
223
224 def test_del_newclass(self):
225 # __del__ methods can trigger collection, make this to happen
226 thresholds = gc.get_threshold()
227 gc.enable()
228 gc.set_threshold(1)
229
230 class A(object):
231 def __del__(self):
232 dir(self)
233 a = A()
234 del a
235
236 gc.disable()
237 gc.set_threshold(*thresholds)
238
239 def test_get_count(self):
Amaury Forgeot d'Arcf67abcc2008-02-15 21:27:44 +0000240 return # disable temporarily
Collin Winterfef1dcf2007-04-06 20:00:05 +0000241 gc.collect()
242 self.assertEqual(gc.get_count(), (0, 0, 0))
243 a = dict()
244 self.assertEqual(gc.get_count(), (1, 0, 0))
245
246 def test_collect_generations(self):
Amaury Forgeot d'Arcf67abcc2008-02-15 21:27:44 +0000247 return # disable temporarily
Collin Winterfef1dcf2007-04-06 20:00:05 +0000248 gc.collect()
249 a = dict()
250 gc.collect(0)
251 self.assertEqual(gc.get_count(), (0, 1, 0))
252 gc.collect(1)
253 self.assertEqual(gc.get_count(), (0, 0, 1))
254 gc.collect(2)
255 self.assertEqual(gc.get_count(), (0, 0, 0))
256
257 def test_trashcan(self):
258 class Ouch:
259 n = 0
260 def __del__(self):
261 Ouch.n = Ouch.n + 1
262 if Ouch.n % 17 == 0:
263 gc.collect()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000264
Collin Winterfef1dcf2007-04-06 20:00:05 +0000265 # "trashcan" is a hack to prevent stack overflow when deallocating
266 # very deeply nested tuples etc. It works in part by abusing the
267 # type pointer and refcount fields, and that can yield horrible
268 # problems when gc tries to traverse the structures.
269 # If this test fails (as it does in 2.0, 2.1 and 2.2), it will
270 # most likely die via segfault.
271
272 # Note: In 2.3 the possibility for compiling without cyclic gc was
273 # removed, and that in turn allows the trashcan mechanism to work
274 # via much simpler means (e.g., it never abuses the type pointer or
275 # refcount fields anymore). Since it's much less likely to cause a
276 # problem now, the various constants in this expensive (we force a lot
277 # of full collections) test are cut back from the 2.2 version.
278 gc.enable()
279 N = 150
280 for count in range(2):
281 t = []
282 for i in range(N):
283 t = [t, Ouch()]
284 u = []
285 for i in range(N):
286 u = [u, Ouch()]
287 v = {}
288 for i in range(N):
289 v = {1: v, 2: Ouch()}
290 gc.disable()
291
292 def test_boom(self):
293 class Boom:
294 def __getattr__(self, someattribute):
295 del self.attr
296 raise AttributeError
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000297
Collin Winterfef1dcf2007-04-06 20:00:05 +0000298 a = Boom()
299 b = Boom()
300 a.attr = b
301 b.attr = a
302
303 gc.collect()
304 garbagelen = len(gc.garbage)
305 del a, b
306 # a<->b are in a trash cycle now. Collection will invoke
307 # Boom.__getattr__ (to see whether a and b have __del__ methods), and
308 # __getattr__ deletes the internal "attr" attributes as a side effect.
309 # That causes the trash cycle to get reclaimed via refcounts falling to
310 # 0, thus mutating the trash graph as a side effect of merely asking
311 # whether __del__ exists. This used to (before 2.3b1) crash Python.
312 # Now __getattr__ isn't called.
313 self.assertEqual(gc.collect(), 4)
314 self.assertEqual(len(gc.garbage), garbagelen)
315
316 def test_boom2(self):
317 class Boom2:
318 def __init__(self):
319 self.x = 0
320
321 def __getattr__(self, someattribute):
322 self.x += 1
323 if self.x > 1:
324 del self.attr
325 raise AttributeError
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000326
Collin Winterfef1dcf2007-04-06 20:00:05 +0000327 a = Boom2()
328 b = Boom2()
329 a.attr = b
330 b.attr = a
331
332 gc.collect()
333 garbagelen = len(gc.garbage)
334 del a, b
335 # Much like test_boom(), except that __getattr__ doesn't break the
336 # cycle until the second time gc checks for __del__. As of 2.3b1,
337 # there isn't a second time, so this simply cleans up the trash cycle.
338 # We expect a, b, a.__dict__ and b.__dict__ (4 objects) to get
339 # reclaimed this way.
340 self.assertEqual(gc.collect(), 4)
341 self.assertEqual(len(gc.garbage), garbagelen)
342
343 def test_boom_new(self):
344 # boom__new and boom2_new are exactly like boom and boom2, except use
345 # new-style classes.
346
347 class Boom_New(object):
348 def __getattr__(self, someattribute):
349 del self.attr
350 raise AttributeError
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000351
Collin Winterfef1dcf2007-04-06 20:00:05 +0000352 a = Boom_New()
353 b = Boom_New()
354 a.attr = b
355 b.attr = a
356
357 gc.collect()
358 garbagelen = len(gc.garbage)
359 del a, b
360 self.assertEqual(gc.collect(), 4)
361 self.assertEqual(len(gc.garbage), garbagelen)
362
363 def test_boom2_new(self):
364 class Boom2_New(object):
365 def __init__(self):
366 self.x = 0
367
368 def __getattr__(self, someattribute):
369 self.x += 1
370 if self.x > 1:
371 del self.attr
372 raise AttributeError
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000373
Collin Winterfef1dcf2007-04-06 20:00:05 +0000374 a = Boom2_New()
375 b = Boom2_New()
376 a.attr = b
377 b.attr = a
378
379 gc.collect()
380 garbagelen = len(gc.garbage)
381 del a, b
382 self.assertEqual(gc.collect(), 4)
383 self.assertEqual(len(gc.garbage), garbagelen)
384
385 def test_get_referents(self):
386 alist = [1, 3, 5]
387 got = gc.get_referents(alist)
388 got.sort()
389 self.assertEqual(got, alist)
390
391 atuple = tuple(alist)
392 got = gc.get_referents(atuple)
393 got.sort()
394 self.assertEqual(got, alist)
395
396 adict = {1: 3, 5: 7}
397 expected = [1, 3, 5, 7]
398 got = gc.get_referents(adict)
399 got.sort()
400 self.assertEqual(got, expected)
401
402 got = gc.get_referents([1, 2], {3: 4}, (0, 0, 0))
403 got.sort()
404 self.assertEqual(got, [0, 0] + range(5))
405
406 self.assertEqual(gc.get_referents(1, 'a', 4j), [])
407
408 def test_bug1055820b(self):
409 # Corresponds to temp2b.py in the bug report.
410
411 ouch = []
412 def callback(ignored):
413 ouch[:] = [wr() for wr in WRs]
414
415 Cs = [C1055820(i) for i in range(2)]
416 WRs = [weakref.ref(c, callback) for c in Cs]
417 c = None
418
419 gc.collect()
420 self.assertEqual(len(ouch), 0)
421 # Make the two instances trash, and collect again. The bug was that
422 # the callback materialized a strong reference to an instance, but gc
423 # cleared the instance's dict anyway.
424 Cs = None
425 gc.collect()
426 self.assertEqual(len(ouch), 2) # else the callbacks didn't run
427 for x in ouch:
428 # If the callback resurrected one of these guys, the instance
429 # would be damaged, with an empty __dict__.
430 self.assertEqual(x, None)
431
432class GCTogglingTests(unittest.TestCase):
433 def setUp(self):
434 gc.enable()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000435
Collin Winterfef1dcf2007-04-06 20:00:05 +0000436 def tearDown(self):
437 gc.disable()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000438
Collin Winterfef1dcf2007-04-06 20:00:05 +0000439 def test_bug1055820c(self):
440 # Corresponds to temp2c.py in the bug report. This is pretty
441 # elaborate.
442
443 c0 = C1055820(0)
444 # Move c0 into generation 2.
445 gc.collect()
446
447 c1 = C1055820(1)
448 c1.keep_c0_alive = c0
449 del c0.loop # now only c1 keeps c0 alive
450
451 c2 = C1055820(2)
452 c2wr = weakref.ref(c2) # no callback!
453
454 ouch = []
455 def callback(ignored):
Tim Petersead8b7a2004-10-30 23:09:22 +0000456 ouch[:] = [c2wr()]
457
Collin Winterfef1dcf2007-04-06 20:00:05 +0000458 # The callback gets associated with a wr on an object in generation 2.
459 c0wr = weakref.ref(c0, callback)
Tim Petersead8b7a2004-10-30 23:09:22 +0000460
Collin Winterfef1dcf2007-04-06 20:00:05 +0000461 c0 = c1 = c2 = None
Tim Petersead8b7a2004-10-30 23:09:22 +0000462
Collin Winterfef1dcf2007-04-06 20:00:05 +0000463 # What we've set up: c0, c1, and c2 are all trash now. c0 is in
464 # generation 2. The only thing keeping it alive is that c1 points to
465 # it. c1 and c2 are in generation 0, and are in self-loops. There's a
466 # global weakref to c2 (c2wr), but that weakref has no callback.
467 # There's also a global weakref to c0 (c0wr), and that does have a
468 # callback, and that callback references c2 via c2wr().
469 #
470 # c0 has a wr with callback, which references c2wr
471 # ^
472 # |
473 # | Generation 2 above dots
474 #. . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .
475 # | Generation 0 below dots
476 # |
477 # |
478 # ^->c1 ^->c2 has a wr but no callback
479 # | | | |
480 # <--v <--v
481 #
482 # So this is the nightmare: when generation 0 gets collected, we see
483 # that c2 has a callback-free weakref, and c1 doesn't even have a
484 # weakref. Collecting generation 0 doesn't see c0 at all, and c0 is
485 # the only object that has a weakref with a callback. gc clears c1
486 # and c2. Clearing c1 has the side effect of dropping the refcount on
487 # c0 to 0, so c0 goes away (despite that it's in an older generation)
488 # and c0's wr callback triggers. That in turn materializes a reference
489 # to c2 via c2wr(), but c2 gets cleared anyway by gc.
Tim Petersead8b7a2004-10-30 23:09:22 +0000490
Collin Winterfef1dcf2007-04-06 20:00:05 +0000491 # We want to let gc happen "naturally", to preserve the distinction
492 # between generations.
493 junk = []
494 i = 0
495 detector = GC_Detector()
496 while not detector.gc_happened:
497 i += 1
498 if i > 10000:
499 self.fail("gc didn't happen after 10000 iterations")
500 self.assertEqual(len(ouch), 0)
501 junk.append([]) # this will eventually trigger gc
Tim Petersead8b7a2004-10-30 23:09:22 +0000502
Collin Winterfef1dcf2007-04-06 20:00:05 +0000503 self.assertEqual(len(ouch), 1) # else the callback wasn't invoked
504 for x in ouch:
505 # If the callback resurrected c2, the instance would be damaged,
506 # with an empty __dict__.
507 self.assertEqual(x, None)
Tim Petersead8b7a2004-10-30 23:09:22 +0000508
Collin Winterfef1dcf2007-04-06 20:00:05 +0000509 def test_bug1055820d(self):
510 # Corresponds to temp2d.py in the bug report. This is very much like
511 # test_bug1055820c, but uses a __del__ method instead of a weakref
512 # callback to sneak in a resurrection of cyclic trash.
Tim Petersead8b7a2004-10-30 23:09:22 +0000513
Collin Winterfef1dcf2007-04-06 20:00:05 +0000514 ouch = []
515 class D(C1055820):
516 def __del__(self):
517 ouch[:] = [c2wr()]
Tim Petersead8b7a2004-10-30 23:09:22 +0000518
Collin Winterfef1dcf2007-04-06 20:00:05 +0000519 d0 = D(0)
520 # Move all the above into generation 2.
521 gc.collect()
Tim Petersead8b7a2004-10-30 23:09:22 +0000522
Collin Winterfef1dcf2007-04-06 20:00:05 +0000523 c1 = C1055820(1)
524 c1.keep_d0_alive = d0
525 del d0.loop # now only c1 keeps d0 alive
Tim Petersead8b7a2004-10-30 23:09:22 +0000526
Collin Winterfef1dcf2007-04-06 20:00:05 +0000527 c2 = C1055820(2)
528 c2wr = weakref.ref(c2) # no callback!
Tim Petersead8b7a2004-10-30 23:09:22 +0000529
Collin Winterfef1dcf2007-04-06 20:00:05 +0000530 d0 = c1 = c2 = None
Vladimir Marangozovf9d20c32000-08-06 22:45:31 +0000531
Collin Winterfef1dcf2007-04-06 20:00:05 +0000532 # What we've set up: d0, c1, and c2 are all trash now. d0 is in
533 # generation 2. The only thing keeping it alive is that c1 points to
534 # it. c1 and c2 are in generation 0, and are in self-loops. There's
535 # a global weakref to c2 (c2wr), but that weakref has no callback.
536 # There are no other weakrefs.
537 #
538 # d0 has a __del__ method that references c2wr
539 # ^
540 # |
541 # | Generation 2 above dots
542 #. . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .
543 # | Generation 0 below dots
544 # |
545 # |
546 # ^->c1 ^->c2 has a wr but no callback
547 # | | | |
548 # <--v <--v
549 #
550 # So this is the nightmare: when generation 0 gets collected, we see
551 # that c2 has a callback-free weakref, and c1 doesn't even have a
552 # weakref. Collecting generation 0 doesn't see d0 at all. gc clears
553 # c1 and c2. Clearing c1 has the side effect of dropping the refcount
554 # on d0 to 0, so d0 goes away (despite that it's in an older
555 # generation) and d0's __del__ triggers. That in turn materializes
556 # a reference to c2 via c2wr(), but c2 gets cleared anyway by gc.
557
558 # We want to let gc happen "naturally", to preserve the distinction
559 # between generations.
560 detector = GC_Detector()
561 junk = []
562 i = 0
563 while not detector.gc_happened:
564 i += 1
565 if i > 10000:
566 self.fail("gc didn't happen after 10000 iterations")
567 self.assertEqual(len(ouch), 0)
568 junk.append([]) # this will eventually trigger gc
569
570 self.assertEqual(len(ouch), 1) # else __del__ wasn't invoked
571 for x in ouch:
572 # If __del__ resurrected c2, the instance would be damaged, with an
573 # empty __dict__.
574 self.assertEqual(x, None)
575
576def test_main():
Vladimir Marangozovf9d20c32000-08-06 22:45:31 +0000577 enabled = gc.isenabled()
578 gc.disable()
Collin Winterfef1dcf2007-04-06 20:00:05 +0000579 assert not gc.isenabled()
Neil Schemenauerfaae2662000-09-22 15:26:20 +0000580 debug = gc.get_debug()
581 gc.set_debug(debug & ~gc.DEBUG_LEAK) # this test is supposed to leak
Vladimir Marangozovf9d20c32000-08-06 22:45:31 +0000582
Neil Schemenauerfaae2662000-09-22 15:26:20 +0000583 try:
Collin Winterfef1dcf2007-04-06 20:00:05 +0000584 gc.collect() # Delete 2nd generation garbage
585 run_unittest(GCTests, GCTogglingTests)
Neil Schemenauerfaae2662000-09-22 15:26:20 +0000586 finally:
587 gc.set_debug(debug)
588 # test gc.enable() even if GC is disabled by default
589 if verbose:
590 print "restoring automatic collection"
591 # make sure to always test gc.enable()
592 gc.enable()
Collin Winterfef1dcf2007-04-06 20:00:05 +0000593 assert gc.isenabled()
Neil Schemenauerfaae2662000-09-22 15:26:20 +0000594 if not enabled:
595 gc.disable()
Neal Norwitz0d4c06e2007-04-25 06:30:05 +0000596
Collin Winterfef1dcf2007-04-06 20:00:05 +0000597if __name__ == "__main__":
598 test_main()