-
-
Notifications
You must be signed in to change notification settings - Fork 33.2k
Description
After RETURN_GENERATOR executes, the new generator's _PyInterpreterFrame has a previous member that still points to the caller's _PyInterpreterFrame. However, this is incorrect; it should be NULL, since the generator's frame isn't actually running anymore. This dangling pointer is dangerous, and can lead to hard crashes of the interpreter. Example:
Python 3.11.0rc2 (tags/v3.11.0rc2:ed7c3ff156, Oct 2 2022, 07:05:44) [GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> def g():
... yield
...
>>> def f():
... return g()
...
>>> gen = f()This should be None, but instead it refers to a dead _PyInterpreterFrame from the previous call:
>>> gen.gi_frame.f_back
<frame at 0x7f74318c6e80, file '<stdin>', line 2, code f>Making other calls "updates" this frame, since it just points to an arbitrary location in the stack:
>>> def spam():
... pass
...
>>> spam()
>>> gen.gi_frame.f_back
<frame at 0x7f7431ab93f0, file '<stdin>', line 2, code spam>It's also quite simple to corrupt:
>>> del spam
>>> gen.gi_frame.f_back
<frame at 0x7f7431ab93f0, file '<stdin>', line 1629515630, code '<stdin>'>
>>> gen.gi_frame.f_back.f_code
Segmentation faultThis bug also appears to affect PyAsyncGen_New, PyCoro_New, PyGen_New, and PyGen_NewWithQualName.
The fix is simple: set frame->previous to NULL after calls to _PyFrame_Copy. I'll open a PR at the sprint tomorrow.
Metadata
Metadata
Assignees
Labels
Projects
Status
Status