Skip to content

Commit 5110780

Browse files
[3.14] pythongh-125996: fix thread safety of collections.OrderedDict (pythonGH-133734) (python#140053)
(cherry picked from commit 6481539)
1 parent 17d9f71 commit 5110780

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
@@ -2770,8 +2770,8 @@ PyDict_DelItem(PyObject *op, PyObject *key)
27702770
return _PyDict_DelItem_KnownHash(op, key, hash);
27712771
}
27722772

2773-
static int
2774-
delitem_knownhash_lock_held(PyObject *op, PyObject *key, Py_hash_t hash)
2773+
int
2774+
_PyDict_DelItem_KnownHash_LockHeld(PyObject *op, PyObject *key, Py_hash_t hash)
27752775
{
27762776
Py_ssize_t ix;
27772777
PyDictObject *mp;
@@ -2806,7 +2806,7 @@ _PyDict_DelItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash)
28062806
{
28072807
int res;
28082808
Py_BEGIN_CRITICAL_SECTION(op);
2809-
res = delitem_knownhash_lock_held(op, key, hash);
2809+
res = _PyDict_DelItem_KnownHash_LockHeld(op, key, hash);
28102810
Py_END_CRITICAL_SECTION();
28112811
return res;
28122812
}
@@ -4654,9 +4654,11 @@ dict_tp_clear(PyObject *op)
46544654

46554655
static PyObject *dictiter_new(PyDictObject *, PyTypeObject *);
46564656

4657-
static Py_ssize_t
4658-
sizeof_lock_held(PyDictObject *mp)
4657+
Py_ssize_t
4658+
_PyDict_SizeOf_LockHeld(PyDictObject *mp)
46594659
{
4660+
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(mp);
4661+
46604662
size_t res = _PyObject_SIZE(Py_TYPE(mp));
46614663
if (_PyDict_HasSplitTable(mp)) {
46624664
res += shared_keys_usable_size(mp->ma_keys) * sizeof(PyObject*);
@@ -4675,7 +4677,7 @@ _PyDict_SizeOf(PyDictObject *mp)
46754677
{
46764678
Py_ssize_t res;
46774679
Py_BEGIN_CRITICAL_SECTION(mp);
4678-
res = sizeof_lock_held(mp);
4680+
res = _PyDict_SizeOf_LockHeld(mp);
46794681
Py_END_CRITICAL_SECTION();
46804682

46814683
return res;
@@ -6865,7 +6867,7 @@ _PyDict_SetItem_LockHeld(PyDictObject *dict, PyObject *name, PyObject *value)
68656867
dict_unhashable_type(name);
68666868
return -1;
68676869
}
6868-
return delitem_knownhash_lock_held((PyObject *)dict, name, hash);
6870+
return _PyDict_DelItem_KnownHash_LockHeld((PyObject *)dict, name, hash);
68696871
} else {
68706872
return setitem_lock_held(dict, name, value);
68716873
}

0 commit comments

Comments
 (0)