@@ -293,71 +293,6 @@ def gen():
293293 """ )
294294 assert_python_ok ("-c" , code )
295295
296- @support .cpython_only
297- @unittest .skipIf (Py_GIL_DISABLED , "test requires precise GC scheduling" )
298- def test_sneaky_frame_object (self ):
299-
300- def trace (frame , event , arg ):
301- """
302- Don't actually do anything, just force a frame object to be created.
303- """
304-
305- def callback (phase , info ):
306- """
307- Yo dawg, I heard you like frames, so I'm allocating a frame while
308- you're allocating a frame, so you can have a frame while you have a
309- frame!
310- """
311- nonlocal sneaky_frame_object
312- sneaky_frame_object = sys ._getframe ().f_back .f_back
313- # We're done here:
314- gc .callbacks .remove (callback )
315-
316- def f ():
317- while True :
318- yield
319-
320- old_threshold = gc .get_threshold ()
321- old_callbacks = gc .callbacks [:]
322- old_enabled = gc .isenabled ()
323- old_trace = sys .gettrace ()
324- try :
325- # Stop the GC for a second while we set things up:
326- gc .disable ()
327- # Create a paused generator:
328- g = f ()
329- next (g )
330- # Move all objects to the oldest generation, and tell the GC to run
331- # on the *very next* allocation:
332- gc .collect ()
333- gc .set_threshold (1 , 0 , 0 )
334- sys ._clear_internal_caches ()
335- # Okay, so here's the nightmare scenario:
336- # - We're tracing the resumption of a generator, which creates a new
337- # frame object.
338- # - The allocation of this frame object triggers a collection
339- # *before* the frame object is actually created.
340- # - During the collection, we request the exact same frame object.
341- # This test does it with a GC callback, but in real code it would
342- # likely be a trace function, weakref callback, or finalizer.
343- # - The collection finishes, and the original frame object is
344- # created. We now have two frame objects fighting over ownership
345- # of the same interpreter frame!
346- sys .settrace (trace )
347- gc .callbacks .append (callback )
348- sneaky_frame_object = None
349- gc .enable ()
350- next (g )
351- # g.gi_frame should be the frame object from the callback (the
352- # one that was *requested* second, but *created* first):
353- self .assertIs (g .gi_frame , sneaky_frame_object )
354- finally :
355- gc .set_threshold (* old_threshold )
356- gc .callbacks [:] = old_callbacks
357- sys .settrace (old_trace )
358- if old_enabled :
359- gc .enable ()
360-
361296 @support .cpython_only
362297 @threading_helper .requires_working_threading ()
363298 def test_sneaky_frame_object_teardown (self ):
0 commit comments