Skip to content
This repository was archived by the owner on May 20, 2025. It is now read-only.

Commit 605f207

Browse files
committed
dict: only use cached keys in thread that created type
Python has a dictionary optimization for object's `__dict__` that tries to share keys between multiple dictionaries. Most of the shared keys code isn't thread safe, so only use it if the current _PyThread_Id() matches the type's owning thread. See #38
1 parent e3e8478 commit 605f207

File tree

1 file changed

+16
-5
lines changed

1 file changed

+16
-5
lines changed

Objects/dictobject.c

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4632,6 +4632,16 @@ _PyDict_NewKeysForClass(void)
46324632

46334633
#define CACHED_KEYS(tp) (((PyHeapTypeObject*)tp)->ht_cached_keys)
46344634

4635+
static PyDictKeysObject *
4636+
_PyTypeObject_CachedKeys(PyTypeObject *tp)
4637+
{
4638+
if ((tp->tp_flags & Py_TPFLAGS_HEAPTYPE) &&
4639+
_PyObject_ThreadId(tp) == _Py_ThreadId()) {
4640+
return ((PyHeapTypeObject*)tp)->ht_cached_keys;
4641+
}
4642+
return NULL;
4643+
}
4644+
46354645
PyObject *
46364646
PyObject_GenericGetDict(PyObject *obj, void *context)
46374647
{
@@ -4643,10 +4653,10 @@ PyObject_GenericGetDict(PyObject *obj, void *context)
46434653
}
46444654
dict = *dictptr;
46454655
if (dict == NULL) {
4646-
PyTypeObject *tp = Py_TYPE(obj);
4647-
if ((tp->tp_flags & Py_TPFLAGS_HEAPTYPE) && CACHED_KEYS(tp)) {
4648-
dictkeys_incref(CACHED_KEYS(tp));
4649-
*dictptr = dict = new_dict_with_shared_keys(CACHED_KEYS(tp));
4656+
PyDictKeysObject *keys = _PyTypeObject_CachedKeys(Py_TYPE(obj));
4657+
if (keys) {
4658+
dictkeys_incref(keys);
4659+
*dictptr = dict = new_dict_with_shared_keys(keys);
46504660
}
46514661
else {
46524662
*dictptr = dict = PyDict_New();
@@ -4665,7 +4675,8 @@ _PyObjectDict_SetItem(PyTypeObject *tp, PyObject **dictptr,
46654675
PyDictKeysObject *cached;
46664676

46674677
assert(dictptr != NULL);
4668-
if ((tp->tp_flags & Py_TPFLAGS_HEAPTYPE) && (cached = CACHED_KEYS(tp))) {
4678+
cached = _PyTypeObject_CachedKeys(tp);
4679+
if (cached) {
46694680
assert(dictptr != NULL);
46704681
dict = *dictptr;
46714682
if (dict == NULL) {

0 commit comments

Comments
 (0)