@@ -1312,16 +1312,21 @@ subtype_traverse(PyObject *self, visitproc visit, void *arg)
13121312 assert (base );
13131313 }
13141314
1315- if (type -> tp_flags & Py_TPFLAGS_MANAGED_DICT ) {
1316- int err = _PyObject_VisitManagedDict (self , visit , arg );
1317- if (err ) {
1318- return err ;
1315+ if (type -> tp_dictoffset != base -> tp_dictoffset ) {
1316+ assert (base -> tp_dictoffset == 0 );
1317+ if (type -> tp_flags & Py_TPFLAGS_MANAGED_DICT ) {
1318+ assert (type -> tp_dictoffset == -1 );
1319+ int err = _PyObject_VisitManagedDict (self , visit , arg );
1320+ if (err ) {
1321+ return err ;
1322+ }
1323+ }
1324+ else {
1325+ PyObject * * dictptr = _PyObject_ComputedDictPointer (self );
1326+ if (dictptr && * dictptr ) {
1327+ Py_VISIT (* dictptr );
1328+ }
13191329 }
1320- }
1321- else if (type -> tp_dictoffset != base -> tp_dictoffset ) {
1322- PyObject * * dictptr = _PyObject_ComputedDictPointer (self );
1323- if (dictptr && * dictptr )
1324- Py_VISIT (* dictptr );
13251330 }
13261331
13271332 if (type -> tp_flags & Py_TPFLAGS_HEAPTYPE
@@ -1380,7 +1385,9 @@ subtype_clear(PyObject *self)
13801385 /* Clear the instance dict (if any), to break cycles involving only
13811386 __dict__ slots (as in the case 'self.__dict__ is self'). */
13821387 if (type -> tp_flags & Py_TPFLAGS_MANAGED_DICT ) {
1383- _PyObject_ClearManagedDict (self );
1388+ if ((base -> tp_flags & Py_TPFLAGS_MANAGED_DICT ) == 0 ) {
1389+ _PyObject_ClearManagedDict (self );
1390+ }
13841391 }
13851392 else if (type -> tp_dictoffset != base -> tp_dictoffset ) {
13861393 PyObject * * dictptr = _PyObject_ComputedDictPointer (self );
@@ -3085,20 +3092,15 @@ type_new_descriptors(const type_new_ctx *ctx, PyTypeObject *type)
30853092 }
30863093 }
30873094
3088- if (ctx -> add_dict && ctx -> base -> tp_itemsize ) {
3089- type -> tp_dictoffset = - (long )sizeof (PyObject * );
3090- slotoffset += sizeof (PyObject * );
3091- }
3092-
30933095 if (ctx -> add_weak ) {
30943096 assert (!ctx -> base -> tp_itemsize );
30953097 type -> tp_weaklistoffset = slotoffset ;
30963098 slotoffset += sizeof (PyObject * );
30973099 }
3098- if (ctx -> add_dict && ctx -> base -> tp_itemsize == 0 ) {
3100+ if (ctx -> add_dict ) {
30993101 assert ((type -> tp_flags & Py_TPFLAGS_MANAGED_DICT ) == 0 );
31003102 type -> tp_flags |= Py_TPFLAGS_MANAGED_DICT ;
3101- type -> tp_dictoffset = - slotoffset - sizeof ( PyObject * ) * 3 ;
3103+ type -> tp_dictoffset = -1 ;
31023104 }
31033105
31043106 type -> tp_basicsize = slotoffset ;
@@ -6161,6 +6163,7 @@ inherit_special(PyTypeObject *type, PyTypeObject *base)
61616163 COPYVAL (tp_itemsize );
61626164 COPYVAL (tp_weaklistoffset );
61636165 COPYVAL (tp_dictoffset );
6166+
61646167#undef COPYVAL
61656168
61666169 /* Setup fast subclass flags */
@@ -6567,6 +6570,21 @@ type_ready_fill_dict(PyTypeObject *type)
65676570 return 0 ;
65686571}
65696572
6573+ static int
6574+ type_ready_dict_offset (PyTypeObject * type )
6575+ {
6576+ if (type -> tp_flags & Py_TPFLAGS_MANAGED_DICT ) {
6577+ if (type -> tp_dictoffset > 0 || type -> tp_dictoffset < -1 ) {
6578+ PyErr_Format (PyExc_TypeError ,
6579+ "type %s has the Py_TPFLAGS_MANAGED_DICT flag "
6580+ "but tp_dictoffset is set" ,
6581+ type -> tp_name );
6582+ return -1 ;
6583+ }
6584+ type -> tp_dictoffset = -1 ;
6585+ }
6586+ return 0 ;
6587+ }
65706588
65716589static int
65726590type_ready_mro (PyTypeObject * type )
@@ -6775,6 +6793,21 @@ type_ready_post_checks(PyTypeObject *type)
67756793 type -> tp_name );
67766794 return -1 ;
67776795 }
6796+ if (type -> tp_flags & Py_TPFLAGS_MANAGED_DICT ) {
6797+ if (type -> tp_dictoffset != -1 ) {
6798+ PyErr_Format (PyExc_SystemError ,
6799+ "type %s has the Py_TPFLAGS_MANAGED_DICT flag "
6800+ "but tp_dictoffset is set to incompatible value" ,
6801+ type -> tp_name );
6802+ return -1 ;
6803+ }
6804+ }
6805+ else if (type -> tp_dictoffset < sizeof (PyObject )) {
6806+ if (type -> tp_dictoffset + type -> tp_basicsize <= 0 ) {
6807+ PyErr_Format (PyExc_SystemError ,
6808+ "type %s has a tp_dictoffset that is too small" );
6809+ }
6810+ }
67786811 return 0 ;
67796812}
67806813
@@ -6814,6 +6847,9 @@ type_ready(PyTypeObject *type)
68146847 if (type_ready_inherit (type ) < 0 ) {
68156848 return -1 ;
68166849 }
6850+ if (type_ready_dict_offset (type ) < 0 ) {
6851+ return -1 ;
6852+ }
68176853 if (type_ready_set_hash (type ) < 0 ) {
68186854 return -1 ;
68196855 }
0 commit comments