Skip to content

Commit a3f89b7

Browse files
committed
Clear inline values upon invalidation
This avoids a race where another thread invalidates the values, overwrites an attribute stored in the values, and allocates a new object at the address present in the values.
1 parent e07fb62 commit a3f89b7

File tree

1 file changed

+20
-3
lines changed

1 file changed

+20
-3
lines changed

Objects/dictobject.c

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1951,6 +1951,17 @@ build_indices_unicode(PyDictKeysObject *keys, PyDictUnicodeEntry *ep, Py_ssize_t
19511951
}
19521952
}
19531953

1954+
1955+
static void
1956+
invalidate_and_clear_inline_values(PyDictValues *values)
1957+
{
1958+
assert(values->embedded);
1959+
FT_ATOMIC_STORE_UINT8(values->valid, 0);
1960+
for (int i = 0; i < values->capacity; i++) {
1961+
FT_ATOMIC_STORE_PTR(values->values[i], NULL);
1962+
}
1963+
}
1964+
19541965
/*
19551966
Restructure the table by allocating a new table and reinserting all
19561967
items again. When entries have been deleted, the new table may
@@ -2042,7 +2053,7 @@ dictresize(PyInterpreterState *interp, PyDictObject *mp,
20422053
if (oldvalues->embedded) {
20432054
assert(oldvalues->embedded == 1);
20442055
assert(oldvalues->valid == 1);
2045-
FT_ATOMIC_STORE_UINT8(oldvalues->valid, 0);
2056+
invalidate_and_clear_inline_values(oldvalues);
20462057
}
20472058
else {
20482059
free_values(oldvalues, IS_DICT_SHARED(mp));
@@ -7032,7 +7043,13 @@ _PyObject_TryGetInstanceAttribute(PyObject *obj, PyObject *name, PyObject **attr
70327043

70337044
#ifdef Py_GIL_DISABLED
70347045
PyObject *value = _Py_atomic_load_ptr_acquire(&values->values[ix]);
7035-
if (value == NULL || _Py_TryIncrefCompare(&values->values[ix], value)) {
7046+
if (value == NULL) {
7047+
if (FT_ATOMIC_LOAD_UINT8(values->valid)) {
7048+
*attr = NULL;
7049+
return true;
7050+
}
7051+
}
7052+
else if (_Py_TryIncrefCompare(&values->values[ix], value)) {
70367053
*attr = value;
70377054
return true;
70387055
}
@@ -7370,7 +7387,7 @@ _PyDict_DetachFromObject(PyDictObject *mp, PyObject *obj)
73707387
}
73717388
mp->ma_values = values;
73727389

7373-
FT_ATOMIC_STORE_UINT8(_PyObject_InlineValues(obj)->valid, 0);
7390+
invalidate_and_clear_inline_values(_PyObject_InlineValues(obj));
73747391

73757392
assert(_PyObject_InlineValuesConsistencyCheck(obj));
73767393
ASSERT_CONSISTENT(mp);

0 commit comments

Comments
 (0)