Skip to content

Commit c815827

Browse files
fix thread safety of ordered dict
1 parent afed5f8 commit c815827

File tree

4 files changed

+258
-64
lines changed

4 files changed

+258
-64
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,

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
}
@@ -4647,9 +4647,11 @@ dict_tp_clear(PyObject *op)
46474647

46484648
static PyObject *dictiter_new(PyDictObject *, PyTypeObject *);
46494649

4650-
static Py_ssize_t
4651-
sizeof_lock_held(PyDictObject *mp)
4650+
Py_ssize_t
4651+
_PyDict_SizeOf_LockHeld(PyDictObject *mp)
46524652
{
4653+
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(mp);
4654+
46534655
size_t res = _PyObject_SIZE(Py_TYPE(mp));
46544656
if (_PyDict_HasSplitTable(mp)) {
46554657
res += shared_keys_usable_size(mp->ma_keys) * sizeof(PyObject*);
@@ -4668,7 +4670,7 @@ _PyDict_SizeOf(PyDictObject *mp)
46684670
{
46694671
Py_ssize_t res;
46704672
Py_BEGIN_CRITICAL_SECTION(mp);
4671-
res = sizeof_lock_held(mp);
4673+
res = _PyDict_SizeOf_LockHeld(mp);
46724674
Py_END_CRITICAL_SECTION();
46734675

46744676
return res;
@@ -6858,7 +6860,7 @@ _PyDict_SetItem_LockHeld(PyDictObject *dict, PyObject *name, PyObject *value)
68586860
dict_unhashable_type(name);
68596861
return -1;
68606862
}
6861-
return delitem_knownhash_lock_held((PyObject *)dict, name, hash);
6863+
return _PyDict_DelItem_KnownHash_LockHeld((PyObject *)dict, name, hash);
68626864
} else {
68636865
return setitem_lock_held(dict, name, value);
68646866
}

0 commit comments

Comments
 (0)