@@ -1567,24 +1567,20 @@ def closed(self):
15671567 def test_reentrant_detach_during_flush (self ):
15681568 # gh-143008: Reentrant detach() during flush should not crash.
15691569 wrapper = None
1570- wrapper_ref = lambda : None
1571-
1572- class EvilBuffer (self .BufferedRandom ):
1573- detach_on_write = False
15741570
1571+ class DetachOnFlush (self .BufferedRandom ):
15751572 def flush (self ):
1576- wrapper = wrapper_ref ()
1577- if wrapper is not None and not self .detach_on_write :
1573+ if wrapper is not None :
15781574 wrapper .detach ()
15791575 return super ().flush ()
15801576
1577+ class DetachOnWrite (self .BufferedRandom ):
15811578 def write (self , b ):
1582- wrapper = wrapper_ref ()
1583- if wrapper is not None and self .detach_on_write :
1579+ if wrapper is not None :
15841580 wrapper .detach ()
15851581 return len (b )
15861582
1587- # Many calls could result in the same null self->buffer crash .
1583+ # Used to crash; now will run out of stack .
15881584 tests = [
15891585 ('truncate' , lambda : wrapper .truncate (0 )),
15901586 ('close' , lambda : wrapper .close ()),
@@ -1593,23 +1589,26 @@ def write(self, b):
15931589 ('tell' , lambda : wrapper .tell ()),
15941590 ('reconfigure' , lambda : wrapper .reconfigure (line_buffering = True )),
15951591 ]
1596- for name , method in tests :
1592+ for name , call in tests :
15971593 with self .subTest (name ), set_recursion_limit (100 ):
1598- wrapper = self .TextIOWrapper (EvilBuffer (self .MockRawIO ()), encoding = 'utf-8' )
1599- wrapper_ref = weakref .ref (wrapper )
1600- # Used to crash; now will run out of stack.
1601- self .assertRaises (RecursionError , method )
1602- wrapper_ref = lambda : None
1603- del wrapper
1594+ buffer = DetachOnFlush (self .MockRawIO ())
1595+ wrapper = self .TextIOWrapper (buffer , encoding = 'utf-8' )
1596+ try :
1597+ self .assertRaises (RecursionError , call )
1598+ finally :
1599+ # Disarm before GC so finalization succeeds.
1600+ wrapper = None
16041601
1602+ # Used to crash.
16051603 with self .subTest ('read via writeflush' ):
1606- EvilBuffer .detach_on_write = True
1607- wrapper = self .TextIOWrapper (EvilBuffer (self .MockRawIO ()), encoding = 'utf-8' )
1608- wrapper_ref = weakref .ref (wrapper )
1609- wrapper .write ('x' )
1610- self .assertRaisesRegex (ValueError , "detached" , wrapper .read )
1611- wrapper_ref = lambda : None
1612- del wrapper
1604+ buffer = DetachOnWrite (self .MockRawIO ())
1605+ wrapper = self .TextIOWrapper (buffer , encoding = 'utf-8' )
1606+ try :
1607+ wrapper .write ('x' )
1608+ self .assertRaisesRegex (ValueError , "detached" , wrapper .read )
1609+ finally :
1610+ # Disarm before GC so finalization succeeds.
1611+ wrapper = None
16131612
16141613
16151614class PyTextIOWrapperTest (TextIOWrapperTest , PyTestCase ):
0 commit comments