head 1.3; access; symbols pkgsrc-2013Q2:1.3.0.52 pkgsrc-2013Q2-base:1.3 pkgsrc-2012Q4:1.3.0.50 pkgsrc-2012Q4-base:1.3 pkgsrc-2011Q4:1.3.0.48 pkgsrc-2011Q4-base:1.3 pkgsrc-2011Q2:1.3.0.46 pkgsrc-2011Q2-base:1.3 pkgsrc-2009Q4:1.3.0.44 pkgsrc-2009Q4-base:1.3 pkgsrc-2008Q4:1.3.0.42 pkgsrc-2008Q4-base:1.3 pkgsrc-2008Q3:1.3.0.40 pkgsrc-2008Q3-base:1.3 cube-native-xorg:1.3.0.38 cube-native-xorg-base:1.3 pkgsrc-2008Q2:1.3.0.36 pkgsrc-2008Q2-base:1.3 pkgsrc-2008Q1:1.3.0.34 pkgsrc-2008Q1-base:1.3 pkgsrc-2007Q4:1.3.0.32 pkgsrc-2007Q4-base:1.3 pkgsrc-2007Q3:1.3.0.30 pkgsrc-2007Q3-base:1.3 pkgsrc-2007Q2:1.3.0.28 pkgsrc-2007Q2-base:1.3 pkgsrc-2007Q1:1.3.0.26 pkgsrc-2007Q1-base:1.3 pkgsrc-2006Q4:1.3.0.24 pkgsrc-2006Q4-base:1.3 pkgsrc-2006Q3:1.3.0.22 pkgsrc-2006Q3-base:1.3 pkgsrc-2006Q2:1.3.0.20 pkgsrc-2006Q2-base:1.3 pkgsrc-2006Q1:1.3.0.18 pkgsrc-2006Q1-base:1.3 pkgsrc-2005Q4:1.3.0.16 pkgsrc-2005Q4-base:1.3 pkgsrc-2005Q3:1.3.0.14 pkgsrc-2005Q3-base:1.3 pkgsrc-2005Q2:1.3.0.12 pkgsrc-2005Q2-base:1.3 pkgsrc-2005Q1:1.3.0.10 pkgsrc-2005Q1-base:1.3 pkgsrc-2004Q4:1.3.0.8 pkgsrc-2004Q4-base:1.3 pkgsrc-2004Q3:1.3.0.6 pkgsrc-2004Q3-base:1.3 pkgsrc-2004Q2:1.3.0.4 pkgsrc-2004Q2-base:1.3 pkgsrc-2004Q1:1.3.0.2 pkgsrc-2004Q1-base:1.3 pkgsrc-2003Q4:1.1.1.1.0.2 pkgsrc-2003Q4-base:1.1.1.1 pkgsrc-base:1.1.1.1 TNF:1.1.1; locks; strict; comment @# @; 1.3 date 2003.12.23.17.24.42; author recht; state dead; branches; next 1.2; 1.2 date 2003.12.08.21.13.56; author recht; state Exp; branches; next 1.1; 1.1 date 2003.08.04.08.29.32; author drochner; state Exp; branches 1.1.1.1; next ; 1.1.1.1 date 2003.08.04.08.29.32; author drochner; state Exp; branches; next ; desc @@ 1.3 log @update to 2.3.3 This is a bug-fix release for Python 2.3 that fixes a number of bugs, including a couple of serious errors with weakrefs and the cyclic garbage collector. There are also a number of fixes to the standard library - see the release notes ( http://www.python.org/2.3.3/NEWS.html )for details. @ text @$NetBSD: patch-ag,v 1.2 2003/12/08 21:13:56 recht Exp $ --- Lib/test/test_weakref.py.orig 2003-07-14 23:37:17.000000000 +0200 +++ Lib/test/test_weakref.py @@@@ -299,6 +299,211 @@@@ class ReferencesTestCase(TestBase): self.fail("exception not properly restored") + def test_callback_in_cycle_1(self): + import gc + + class J(object): + pass + + class II(object): + def acallback(self, ignore): + self.J + + I = II() + I.J = J + I.wr = weakref.ref(J, I.acallback) + + # Now J and II are each in a self-cycle (as all new-style class + # objects are, since their __mro__ points back to them). I holds + # both a weak reference (I.wr) and a strong reference (I.J) to class + # J. I is also in a cycle (I.wr points to a weakref that references + # I.acallback). When we del these three, they all become trash, but + # the cycles prevent any of them from getting cleaned up immediately. + # Instead they have to wait for cyclic gc to deduce that they're + # trash. + # + # gc used to call tp_clear on all of them, and the order in which + # it does that is pretty accidental. The exact order in which we + # built up these things manages to provoke gc into running tp_clear + # in just the right order (I last). Calling tp_clear on II leaves + # behind an insane class object (its __mro__ becomes NULL). Calling + # tp_clear on J breaks its self-cycle, but J doesn't get deleted + # just then because of the strong reference from I.J. Calling + # tp_clear on I starts to clear I's __dict__, and just happens to + # clear I.J first -- I.wr is still intact. That removes the last + # reference to J, which triggers the weakref callback. The callback + # tries to do "self.J", and instances of new-style classes look up + # attributes ("J") in the class dict first. The class (II) wants to + # search II.__mro__, but that's NULL. The result was a segfault in + # a release build, and an assert failure in a debug build. + del I, J, II + gc.collect() + + def test_callback_in_cycle_2(self): + import gc + + # This is just like test_callback_in_cycle_1, except that II is an + # old-style class. The symptom is different then: an instance of an + # old-style class looks in its own __dict__ first. 'J' happens to + # get cleared from I.__dict__ before 'wr', and 'J' was never in II's + # __dict__, so the attribute isn't found. The difference is that + # the old-style II doesn't have a NULL __mro__ (it doesn't have any + # __mro__), so no segfault occurs. Instead it got: + # test_callback_in_cycle_2 (__main__.ReferencesTestCase) ... + # Exception exceptions.AttributeError: + # "II instance has no attribute 'J'" in > ignored + + class J(object): + pass + + class II: + def acallback(self, ignore): + self.J + + I = II() + I.J = J + I.wr = weakref.ref(J, I.acallback) + + del I, J, II + gc.collect() + + def test_callback_in_cycle_3(self): + import gc + + # This one broke the first patch that fixed the last two. In this + # case, the objects reachable from the callback aren't also reachable + # from the object (c1) *triggering* the callback: you can get to + # c1 from c2, but not vice-versa. The result was that c2's __dict__ + # got tp_clear'ed by the time the c2.cb callback got invoked. + + class C: + def cb(self, ignore): + self.me + self.c1 + self.wr + + c1, c2 = C(), C() + + c2.me = c2 + c2.c1 = c1 + c2.wr = weakref.ref(c1, c2.cb) + + del c1, c2 + gc.collect() + + def test_callback_in_cycle_4(self): + import gc + + # Like test_callback_in_cycle_3, except c2 and c1 have different + # classes. c2's class (C) isn't reachable from c1 then, so protecting + # objects reachable from the dying object (c1) isn't enough to stop + # c2's class (C) from getting tp_clear'ed before c2.cb is invoked. + # The result was a segfault (C.__mro__ was NULL when the callback + # tried to look up self.me). + + class C(object): + def cb(self, ignore): + self.me + self.c1 + self.wr + + class D: + pass + + c1, c2 = D(), C() + + c2.me = c2 + c2.c1 = c1 + c2.wr = weakref.ref(c1, c2.cb) + + del c1, c2, C, D + gc.collect() + + def test_callback_in_cycle_resurrection(self): + import gc + + # Do something nasty in a weakref callback: resurrect objects + # from dead cycles. For this to be attempted, the weakref and + # its callback must also be part of the cyclic trash (else the + # objects reachable via the callback couldn't be in cyclic trash + # to begin with -- the callback would act like an external root). + # But gc clears trash weakrefs with callbacks early now, which + # disables the callbacks, so the callbacks shouldn't get called + # at all (and so nothing actually gets resurrected). + + alist = [] + class C(object): + def __init__(self, value): + self.attribute = value + + def acallback(self, ignore): + alist.append(self.c) + + c1, c2 = C(1), C(2) + c1.c = c2 + c2.c = c1 + c1.wr = weakref.ref(c2, c1.acallback) + c2.wr = weakref.ref(c1, c2.acallback) + + def C_went_away(ignore): + alist.append("C went away") + wr = weakref.ref(C, C_went_away) + + del c1, c2, C # make them all trash + self.assertEqual(alist, []) # del isn't enough to reclaim anything + + gc.collect() + # c1.wr and c2.wr were part of the cyclic trash, so should have + # been cleared without their callbacks executing. OTOH, the weakref + # to C is bound to a function local (wr), and wasn't trash, so that + # callback should have been invoked when C went away. + self.assertEqual(alist, ["C went away"]) + # The remaining weakref should be dead now (its callback ran). + self.assertEqual(wr(), None) + + del alist[:] + gc.collect() + self.assertEqual(alist, []) + + def test_callbacks_on_callback(self): + import gc + + # Set up weakref callbacks *on* weakref callbacks. + alist = [] + def safe_callback(ignore): + alist.append("safe_callback called") + + class C(object): + def cb(self, ignore): + alist.append("cb called") + + c, d = C(), C() + c.other = d + d.other = c + callback = c.cb + c.wr = weakref.ref(d, callback) # this won't trigger + d.wr = weakref.ref(callback, d.cb) # ditto + external_wr = weakref.ref(callback, safe_callback) # but this will + self.assert_(external_wr() is callback) + + # The weakrefs attached to c and d should get cleared, so that + # C.cb is never called. But external_wr isn't part of the cyclic + # trash, and no cyclic trash is reachable from it, so safe_callback + # should get invoked when the bound method object callback (c.cb) + # -- which is itself a callback, and also part of the cyclic trash -- + # gets reclaimed at the end of gc. + + del callback, c, d, C + self.assertEqual(alist, []) # del isn't enough to clean up cycles + gc.collect() + self.assertEqual(alist, ["safe_callback called"]) + self.assertEqual(external_wr(), None) + + del alist[:] + gc.collect() + self.assertEqual(alist, []) + class Object: def __init__(self, arg): self.arg = arg @ 1.2 log @Update to Python 2.3.2 Changes in Python: Quite a few fixes.. See NEWS for details. Changes in the pkg: - add FreeBSD patches from the FreeBSD port - add fix for a fatal bug in type's GC handling causes segfaults (via FreeBSD port) see http://cvs.sourceforge.net/viewcvs.py/python/python/dist/src/Misc/NEWS?r1=1.831.4.75&r2=1.831.4.76&diff_format=u - always build the db 1.85 module (on all platforms) @ text @d1 1 a1 1 $NetBSD$ @ 1.1 log @Initial revision @ text @d3 4 a6 4 --- configure.orig 2003-08-03 13:46:44.000000000 +0200 +++ configure 2003-08-03 13:47:19.000000000 +0200 @@@@ -1243,7 +1243,7 @@@@ mv confdefs.h.new confdefs.h d9 208 a216 5 -VERSION=2.3 +VERSION=2p3 SOVERSION=1.0 @ 1.1.1.1 log @Python-2.3 with thread support. Tested on -current/i386 only so far (this means, GNU pth support is untested). Suffers from stack shortage problems, thus doesn't get far in its selftest suite. @ text @@