@@ -4637,6 +4637,32 @@ check_basicsize_includes_size_and_offsets(PyTypeObject* type)
46374637 return 1 ;
46384638}
46394639
4640+ static int
4641+ check_immutable_bases (const char * type_name , PyObject * bases , int skip_first )
4642+ {
4643+ Py_ssize_t i = 0 ;
4644+ if (skip_first ) {
4645+ // When testing the MRO, skip the type itself
4646+ i = 1 ;
4647+ }
4648+ for (; i < PyTuple_GET_SIZE (bases ); i ++ ) {
4649+ PyTypeObject * b = (PyTypeObject * )PyTuple_GET_ITEM (bases , i );
4650+ if (!b ) {
4651+ return -1 ;
4652+ }
4653+ if (!_PyType_HasFeature (b , Py_TPFLAGS_IMMUTABLETYPE )) {
4654+ PyErr_Format (
4655+ PyExc_TypeError ,
4656+ "Creating immutable type %s from mutable base %N" ,
4657+ type_name , b
4658+ );
4659+ return -1 ;
4660+ }
4661+ }
4662+ return 0 ;
4663+ }
4664+
4665+
46404666/* Set *dest to the offset specified by a special "__*offset__" member.
46414667 * Return 0 on success, -1 on failure.
46424668 */
@@ -4820,19 +4846,8 @@ PyType_FromMetaclass(
48204846 * and only heap types can be mutable.)
48214847 */
48224848 if (spec -> flags & Py_TPFLAGS_IMMUTABLETYPE ) {
4823- for (int i = 0 ; i < PyTuple_GET_SIZE (bases ); i ++ ) {
4824- PyTypeObject * b = (PyTypeObject * )PyTuple_GET_ITEM (bases , i );
4825- if (!b ) {
4826- goto finally ;
4827- }
4828- if (!_PyType_HasFeature (b , Py_TPFLAGS_IMMUTABLETYPE )) {
4829- PyErr_Format (
4830- PyExc_TypeError ,
4831- "Creating immutable type %s from mutable base %N" ,
4832- spec -> name , b
4833- );
4834- goto finally ;
4835- }
4849+ if (check_immutable_bases (spec -> name , bases , 0 ) < 0 ) {
4850+ goto finally ;
48364851 }
48374852 }
48384853
@@ -11319,6 +11334,30 @@ add_operators(PyTypeObject *type)
1131911334}
1132011335
1132111336
11337+ int
11338+ PyType_Freeze (PyTypeObject * type )
11339+ {
11340+ // gh-121654: Check the __mro__ instead of __bases__
11341+ PyObject * mro = type_get_mro (type , NULL );
11342+ if (!PyTuple_Check (mro )) {
11343+ Py_DECREF (mro );
11344+ PyErr_SetString (PyExc_TypeError , "unable to get the type MRO" );
11345+ return -1 ;
11346+ }
11347+
11348+ int check = check_immutable_bases (type -> tp_name , mro , 1 );
11349+ Py_DECREF (mro );
11350+ if (check < 0 ) {
11351+ return -1 ;
11352+ }
11353+
11354+ type -> tp_flags |= Py_TPFLAGS_IMMUTABLETYPE ;
11355+ PyType_Modified (type );
11356+
11357+ return 0 ;
11358+ }
11359+
11360+
1132211361/* Cooperative 'super' */
1132311362
1132411363typedef struct {
0 commit comments