Skip to content

Commit 459e29e

Browse files
committed
Make sure that instance dicts are GC tracked when necessary.
1 parent 7b2efa4 commit 459e29e

File tree

3 files changed

+32
-21
lines changed

3 files changed

+32
-21
lines changed

Objects/dictobject.c

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4969,10 +4969,19 @@ make_dict_from_instance_attributes(PyDictKeysObject *keys, PyDictValues *values)
49694969
{
49704970
dictkeys_incref(keys);
49714971
Py_ssize_t used = 0;
4972+
Py_ssize_t track = 0;
49724973
for (Py_ssize_t i = 0; i < shared_keys_usable_size(keys); i++) {
4973-
used += values->values[i] != NULL;
4974+
PyObject *val = values->values[i];
4975+
if (val != NULL) {
4976+
used += 1;
4977+
track += _PyObject_GC_MAY_BE_TRACKED(val);
4978+
}
4979+
}
4980+
PyObject *res = new_dict(keys, values, used, 0);
4981+
if (track && res) {
4982+
_PyObject_GC_TRACK(res);
49744983
}
4975-
return new_dict(keys, values, used, 0);
4984+
return res;
49764985
}
49774986

49784987
PyObject *
@@ -5025,7 +5034,6 @@ _PyObject_StoreInstanceAttribute(PyObject *obj, PyDictValues *values,
50255034
return 0;
50265035
}
50275036

5028-
50295037
PyObject *
50305038
_PyObject_GetInstanceAttribute(PyObject *obj, PyDictValues *values,
50315039
PyObject *name)
@@ -5072,8 +5080,9 @@ int
50725080
_PyObject_VisitInstanceAttributes(PyObject *self, visitproc visit, void *arg)
50735081
{
50745082
PyTypeObject *tp = Py_TYPE(self);
5083+
assert(tp->tp_inline_values_offset);
50755084
PyDictValues **values_ptr = _PyObject_ValuesPointer(self);
5076-
if (values_ptr == NULL || *values_ptr == NULL) {
5085+
if (*values_ptr == NULL) {
50775086
return 0;
50785087
}
50795088
PyDictKeysObject *keys = CACHED_KEYS(tp);
@@ -5087,8 +5096,9 @@ void
50875096
_PyObject_ClearInstanceAttributes(PyObject *self)
50885097
{
50895098
PyTypeObject *tp = Py_TYPE(self);
5099+
assert(tp->tp_inline_values_offset);
50905100
PyDictValues **values_ptr = _PyObject_ValuesPointer(self);
5091-
if (values_ptr == NULL || *values_ptr == NULL) {
5101+
if (*values_ptr == NULL) {
50925102
return;
50935103
}
50945104
PyDictKeysObject *keys = CACHED_KEYS(tp);
@@ -5101,8 +5111,9 @@ void
51015111
_PyObject_FreeInstanceAttributes(PyObject *self)
51025112
{
51035113
PyTypeObject *tp = Py_TYPE(self);
5114+
assert(tp->tp_inline_values_offset);
51045115
PyDictValues **values_ptr = _PyObject_ValuesPointer(self);
5105-
if (values_ptr == NULL || *values_ptr == NULL) {
5116+
if (*values_ptr == NULL) {
51065117
return;
51075118
}
51085119
PyDictKeysObject *keys = CACHED_KEYS(tp);

Objects/object.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1100,7 +1100,7 @@ _PyObject_GetDictPtr(PyObject *obj)
11001100
return NULL;
11011101
}
11021102
if (*dict_ptr != NULL) {
1103-
return (PyObject **)dict_ptr;
1103+
return dict_ptr;
11041104
}
11051105
PyDictValues **values_ptr = _PyObject_ValuesPointer(obj);
11061106
if (values_ptr == NULL || *values_ptr == NULL) {
@@ -1111,6 +1111,8 @@ _PyObject_GetDictPtr(PyObject *obj)
11111111
PyErr_Clear();
11121112
return NULL;
11131113
}
1114+
assert(*dict_ptr == NULL);
1115+
assert(*values_ptr != NULL);
11141116
*values_ptr = NULL;
11151117
*dict_ptr = dict;
11161118
return dict_ptr;

Objects/typeobject.c

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1232,7 +1232,8 @@ subtype_traverse(PyObject *self, visitproc visit, void *arg)
12321232
assert(base);
12331233
}
12341234

1235-
if (type->tp_inline_values_offset != base->tp_inline_values_offset) {
1235+
if (type->tp_inline_values_offset) {
1236+
assert(type->tp_dictoffset);
12361237
int err = _PyObject_VisitInstanceAttributes(self, visit, arg);
12371238
if (err) {
12381239
return err;
@@ -1300,7 +1301,7 @@ subtype_clear(PyObject *self)
13001301

13011302
/* Clear the instance dict (if any), to break cycles involving only
13021303
__dict__ slots (as in the case 'self.__dict__ is self'). */
1303-
if (type->tp_inline_values_offset != base->tp_inline_values_offset) {
1304+
if (type->tp_inline_values_offset) {
13041305
_PyObject_ClearInstanceAttributes(self);
13051306
}
13061307
if (type->tp_dictoffset != base->tp_dictoffset) {
@@ -1444,7 +1445,7 @@ subtype_dealloc(PyObject *self)
14441445
}
14451446

14461447
/* If we added a dict, DECREF it, or free inline values. */
1447-
if (type->tp_inline_values_offset != base->tp_inline_values_offset) {
1448+
if (type->tp_inline_values_offset) {
14481449
_PyObject_FreeInstanceAttributes(self);
14491450
}
14501451
if (type->tp_dictoffset && !base->tp_dictoffset) {
@@ -4940,17 +4941,14 @@ _PyObject_GetState(PyObject *obj, int required)
49404941
Py_TYPE(obj)->tp_name);
49414942
return NULL;
49424943
}
4943-
4944-
{
4945-
if (_PyObject_DictEmpty(obj)) {
4946-
state = Py_None;
4947-
Py_INCREF(state);
4948-
}
4949-
else {
4950-
state = PyObject_GenericGetDict(obj, NULL);
4951-
if (state == NULL) {
4952-
return NULL;
4953-
}
4944+
if (_PyObject_DictEmpty(obj)) {
4945+
state = Py_None;
4946+
Py_INCREF(state);
4947+
}
4948+
else {
4949+
state = PyObject_GenericGetDict(obj, NULL);
4950+
if (state == NULL) {
4951+
return NULL;
49544952
}
49554953
}
49564954

0 commit comments

Comments
 (0)