-
-
Notifications
You must be signed in to change notification settings - Fork 32k
gh-124470: Fix crash when reading from object instance dictionary while replacing it #122489
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
c26d357
to
5a1b6fd
Compare
16ca39f
to
0988d1a
Compare
0169a30
to
bd1c1a7
Compare
0146a13
to
2d05896
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The overall approach makes sense to me. A few comments below.
Objects/dictobject.c
Outdated
} | ||
|
||
FT_ATOMIC_STORE_PTR(_PyObject_ManagedDictPointer(obj)->dict, | ||
(PyDictObject *)Py_XNewRef(new_dict)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: align (PyDictObject *)Py_XNewRef(new_dict)
1a199bf
to
dc3d5ae
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. A few minor comments below
Include/refcount.h
Outdated
@@ -285,6 +285,7 @@ PyAPI_FUNC(void) _Py_DecRefSharedDebug(PyObject *, const char *, int); | |||
// zero. Otherwise, the thread gives up ownership and merges the reference | |||
// count fields. | |||
PyAPI_FUNC(void) _Py_MergeZeroLocalRefcount(PyObject *); | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Stray whitespace change
} | ||
|
||
static int | ||
set_or_clear_managed_dict(PyObject *obj, PyObject *new_dict, bool clear) | ||
{ | ||
assert(Py_TYPE(obj)->tp_flags & Py_TPFLAGS_MANAGED_DICT); | ||
assert(_PyObject_InlineValuesConsistencyCheck(obj)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do these consistency checks need to be within some sort of lock?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The type flag one is fine, I'll add some ifdefs and lock for the inline check.
Objects/dictobject.c
Outdated
FT_ATOMIC_STORE_PTR(_PyObject_ManagedDictPointer(obj)->dict, | ||
(PyDictObject *)Py_XNewRef(new_dict)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe align the wrapped line
🤖 New build scheduled with the buildbot fleet by @colesbury for commit dc3d5ae 🤖 If you want to schedule another build, you need to add the 🔨 test-with-refleak-buildbots label again. |
117a19e
to
367e1f4
Compare
367e1f4
to
c9aee55
Compare
…ry while replacing it (python#122489) Delay free a dictionary when replacing it
Currently when we have one thread reading an attribute from an object and another thread replacing the dictionary we can crash. This is because the reader thread is actually using a borrowed reference to the object and the writer will decref the dictionary and de-allocate it when replacing the dictionary.
This fixes this by changing the decref of the previous dictionary to be delayed via QSBR. We get rid of the
GC_SET_SHARED_INLINE
flag which is not being used anywhere and instead we simply queue the decref via_PyObject_XDecRefDelayed
.When we process these objects during GC we need to be careful because we don't want to run object finalizers during the destruction of the objects. Instead we do the same thing we do w/ merged dec refs and queue the objects to be decref'd once the world has resumed.