Skip to content

Commit 286eafd

Browse files
committed
fix
1 parent 399d810 commit 286eafd

1 file changed

Lines changed: 24 additions & 13 deletions

File tree

Objects/dictobject.c

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4148,8 +4148,11 @@ dict_dict_merge(PyDictObject *mp, PyDictObject *other, int override, PyObject **
41484148
STORE_USED(mp, other->ma_used);
41494149
ASSERT_CONSISTENT(mp);
41504150

4151-
if (_PyObject_GC_IS_TRACKED(other) && !_PyObject_GC_IS_TRACKED(mp)) {
4152-
/* Maintain tracking. */
4151+
if (_PyObject_GC_IS_TRACKED(other) && !_PyObject_GC_IS_TRACKED(mp)
4152+
&& !PyFrozenDict_Check(mp)) {
4153+
/* Maintain tracking. A frozendict is left untracked while it is
4154+
built and GC-tracked once by its constructor when fully
4155+
built, so don't track it here. */
41534156
_PyObject_GC_TRACK(mp);
41544157
}
41554158

@@ -5357,8 +5360,7 @@ frozendict_vectorcall(PyObject *type, PyObject * const*args,
53575360
}
53585361
}
53595362
}
5360-
/* Track only once fully built. Only ever reached for the exact frozendict
5361-
type, so self is still untracked here. */
5363+
assert(!_PyObject_GC_IS_TRACKED(self));
53625364
_PyObject_GC_TRACK(self);
53635365
return self;
53645366
}
@@ -8378,17 +8380,28 @@ frozendict_hash(PyObject *op)
83788380
}
83798381

83808382

8381-
/* Allocate an empty, GC-untracked frozendict. Staying untracked while it is
8382-
filled keeps a half-built frozendict so another thread can't observe it
8383-
changing. Callers must GC-track it once fully built. */
8383+
/* Allocate an empty, GC-untracked frozendict. Allocation never tracks the
8384+
object -- even for subclasses, whose tp_alloc is PyType_GenericAlloc -- so it
8385+
stays untracked for the whole construction and a half-built frozendict is kept
8386+
out of gc.get_objects(). The constructor GC-tracks it exactly once, when
8387+
fully built. */
83848388
static PyObject *
83858389
frozendict_new_untracked(PyTypeObject *type)
83868390
{
8387-
PyObject *d = dict_new_untracked(type);
8391+
assert(_PyType_IS_GC(type));
8392+
PyObject *d = _PyType_AllocNoTrack(type, 0);
83888393
if (d == NULL) {
83898394
return NULL;
83908395
}
8391-
assert(can_modify_dict(_PyAnyDict_CAST(d)));
8396+
PyDictObject *mp = (PyDictObject *)d;
8397+
mp->ma_used = 0;
8398+
mp->_ma_watcher_tag = 0;
8399+
// Py_EMPTY_KEYS is immortal, so it is not incref'd.
8400+
assert((Py_EMPTY_KEYS)->dk_refcnt == _Py_DICT_IMMORTAL_INITIAL_REFCNT);
8401+
mp->ma_keys = Py_EMPTY_KEYS;
8402+
mp->ma_values = NULL;
8403+
ASSERT_CONSISTENT(mp);
8404+
assert(can_modify_dict(mp));
83928405
_PyFrozenDictObject_CAST(d)->ma_hash = -1;
83938406
return d;
83948407
}
@@ -8411,10 +8424,8 @@ frozendict_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
84118424
assert(kwds == NULL);
84128425
}
84138426

8414-
/* Track only once fully built. */
8415-
if (!_PyObject_GC_IS_TRACKED(d)) {
8416-
_PyObject_GC_TRACK(d);
8417-
}
8427+
assert(!_PyObject_GC_IS_TRACKED(d));
8428+
_PyObject_GC_TRACK(d);
84188429
return d;
84198430
}
84208431

0 commit comments

Comments
 (0)