gh-128421: Add locking to most frame object functions (gh-131479)

This makes more operations on frame objects thread-safe in the free
threaded build, which fixes some data races that occurred when passing
exceptions between threads.

However, accessing local variables from another thread while its running
is still not thread-safe and may crash the interpreter.
This commit is contained in:
Sam Gross 2025-03-21 11:10:07 -04:00 committed by GitHub
parent 5d8e981c84
commit 4f32516804
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 668 additions and 126 deletions

View file

@ -49,6 +49,7 @@ _PyFrame_MakeAndSetFrameObject(_PyInterpreterFrame *frame)
static void
take_ownership(PyFrameObject *f, _PyInterpreterFrame *frame)
{
Py_BEGIN_CRITICAL_SECTION(f);
assert(frame->owner < FRAME_OWNED_BY_INTERPRETER);
assert(frame->owner != FRAME_OWNED_BY_FRAME_OBJECT);
_PyInterpreterFrame *new_frame = (_PyInterpreterFrame *)f->_f_frame_data;
@ -85,6 +86,7 @@ take_ownership(PyFrameObject *f, _PyInterpreterFrame *frame)
if (!_PyObject_GC_IS_TRACKED((PyObject *)f)) {
_PyObject_GC_TRACK((PyObject *)f);
}
Py_END_CRITICAL_SECTION();
}
void
@ -114,7 +116,7 @@ _PyFrame_ClearExceptCode(_PyInterpreterFrame *frame)
if (frame->frame_obj) {
PyFrameObject *f = frame->frame_obj;
frame->frame_obj = NULL;
if (Py_REFCNT(f) > 1) {
if (!_PyObject_IsUniquelyReferenced((PyObject *)f)) {
take_ownership(f, frame);
Py_DECREF(f);
return;