summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>2023-08-01 10:21:08 (GMT)
committerGitHub <noreply@github.com>2023-08-01 10:21:08 (GMT)
commit46cae02085311481dc8b1ea9a5110969d9325bc7 (patch)
tree709a80fe427599393e738efbcaf653d66f6e5f6b
parent3be07c98b3e22601a5837ce25c04803ba63a1aa6 (diff)
downloadcpython-46cae02085311481dc8b1ea9a5110969d9325bc7.zip
cpython-46cae02085311481dc8b1ea9a5110969d9325bc7.tar.gz
cpython-46cae02085311481dc8b1ea9a5110969d9325bc7.tar.bz2
[3.11] gh-106092: Fix use-after-free crash in frame_dealloc (GH-106875) (#107533)
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2023-07-18-16-13-51.gh-issue-106092.bObgRM.rst2
-rw-r--r--Objects/frameobject.c13
2 files changed, 9 insertions, 6 deletions
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-18-16-13-51.gh-issue-106092.bObgRM.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-18-16-13-51.gh-issue-106092.bObgRM.rst
new file mode 100644
index 0000000..7fb5b45
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-07-18-16-13-51.gh-issue-106092.bObgRM.rst
@@ -0,0 +1,2 @@
+Fix a segmentation fault caused by a use-after-free bug in ``frame_dealloc``
+when the trashcan delays the deallocation of a ``PyFrameObject``.
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index 1e6bdcf..425749d 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -851,9 +851,6 @@ frame_dealloc(PyFrameObject *f)
/* It is the responsibility of the owning generator/coroutine
* to have cleared the generator pointer */
- assert(f->f_frame->owner != FRAME_OWNED_BY_GENERATOR ||
- _PyFrame_GetGenerator(f->f_frame)->gi_frame_state == FRAME_CLEARED);
-
if (_PyObject_GC_IS_TRACKED(f)) {
_PyObject_GC_UNTRACK(f);
}
@@ -861,10 +858,14 @@ frame_dealloc(PyFrameObject *f)
Py_TRASHCAN_BEGIN(f, frame_dealloc);
PyCodeObject *co = NULL;
+ /* GH-106092: If f->f_frame was on the stack and we reached the maximum
+ * nesting depth for deallocations, the trashcan may have delayed this
+ * deallocation until after f->f_frame is freed. Avoid dereferencing
+ * f->f_frame unless we know it still points to valid memory. */
+ _PyInterpreterFrame *frame = (_PyInterpreterFrame *)f->_f_frame_data;
+
/* Kill all local variables including specials, if we own them */
- if (f->f_frame->owner == FRAME_OWNED_BY_FRAME_OBJECT) {
- assert(f->f_frame == (_PyInterpreterFrame *)f->_f_frame_data);
- _PyInterpreterFrame *frame = (_PyInterpreterFrame *)f->_f_frame_data;
+ if (f->f_frame == frame && frame->owner == FRAME_OWNED_BY_FRAME_OBJECT) {
/* Don't clear code object until the end */
co = frame->f_code;
frame->f_code = NULL;