Skip to content

Commit 6481539

Browse files
gh-125996: fix thread safety of collections.OrderedDict (#133734)
1 parent 525dcfe commit 6481539

File tree

5 files changed

+266
-76
lines changed

5 files changed

+266
-76
lines changed

Include/internal/pycore_dict.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ PyAPI_FUNC(int) _PyDict_SetItem_KnownHash(PyObject *mp, PyObject *key,
3030
// Export for '_asyncio' shared extension
3131
PyAPI_FUNC(int) _PyDict_DelItem_KnownHash(PyObject *mp, PyObject *key,
3232
Py_hash_t hash);
33+
34+
extern int _PyDict_DelItem_KnownHash_LockHeld(PyObject *mp, PyObject *key,
35+
Py_hash_t hash);
36+
3337
extern int _PyDict_Contains_KnownHash(PyObject *, PyObject *, Py_hash_t);
3438

3539
// "Id" variants
@@ -47,6 +51,8 @@ extern int _PyDict_HasOnlyStringKeys(PyObject *mp);
4751
// Export for '_ctypes' shared extension
4852
PyAPI_FUNC(Py_ssize_t) _PyDict_SizeOf(PyDictObject *);
4953

54+
extern Py_ssize_t _PyDict_SizeOf_LockHeld(PyDictObject *);
55+
5056
#define _PyDict_HasSplitTable(d) ((d)->ma_values != NULL)
5157

5258
/* Like PyDict_Merge, but override can be 0, 1 or 2. If override is 0,
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix thread safety of :class:`collections.OrderedDict`. Patch by Kumar Aditya.

Objects/clinic/odictobject.c.h

Lines changed: 105 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Objects/dictobject.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2819,8 +2819,8 @@ PyDict_DelItem(PyObject *op, PyObject *key)
28192819
return _PyDict_DelItem_KnownHash(op, key, hash);
28202820
}
28212821

2822-
static int
2823-
delitem_knownhash_lock_held(PyObject *op, PyObject *key, Py_hash_t hash)
2822+
int
2823+
_PyDict_DelItem_KnownHash_LockHeld(PyObject *op, PyObject *key, Py_hash_t hash)
28242824
{
28252825
Py_ssize_t ix;
28262826
PyDictObject *mp;
@@ -2855,7 +2855,7 @@ _PyDict_DelItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash)
28552855
{
28562856
int res;
28572857
Py_BEGIN_CRITICAL_SECTION(op);
2858-
res = delitem_knownhash_lock_held(op, key, hash);
2858+
res = _PyDict_DelItem_KnownHash_LockHeld(op, key, hash);
28592859
Py_END_CRITICAL_SECTION();
28602860
return res;
28612861
}
@@ -4703,9 +4703,11 @@ dict_tp_clear(PyObject *op)
47034703

47044704
static PyObject *dictiter_new(PyDictObject *, PyTypeObject *);
47054705

4706-
static Py_ssize_t
4707-
sizeof_lock_held(PyDictObject *mp)
4706+
Py_ssize_t
4707+
_PyDict_SizeOf_LockHeld(PyDictObject *mp)
47084708
{
4709+
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(mp);
4710+
47094711
size_t res = _PyObject_SIZE(Py_TYPE(mp));
47104712
if (_PyDict_HasSplitTable(mp)) {
47114713
res += shared_keys_usable_size(mp->ma_keys) * sizeof(PyObject*);
@@ -4724,7 +4726,7 @@ _PyDict_SizeOf(PyDictObject *mp)
47244726
{
47254727
Py_ssize_t res;
47264728
Py_BEGIN_CRITICAL_SECTION(mp);
4727-
res = sizeof_lock_held(mp);
4729+
res = _PyDict_SizeOf_LockHeld(mp);
47284730
Py_END_CRITICAL_SECTION();
47294731

47304732
return res;
@@ -6909,7 +6911,7 @@ _PyDict_SetItem_LockHeld(PyDictObject *dict, PyObject *name, PyObject *value)
69096911
dict_unhashable_type(name);
69106912
return -1;
69116913
}
6912-
return delitem_knownhash_lock_held((PyObject *)dict, name, hash);
6914+
return _PyDict_DelItem_KnownHash_LockHeld((PyObject *)dict, name, hash);
69136915
} else {
69146916
return setitem_lock_held(dict, name, value);
69156917
}

0 commit comments

Comments
 (0)