Skip to content

Commit 8b8673f

Browse files
authored
[3.10] bpo-46433: _PyType_GetModuleByDef: handle static types in MRO (GH-30696) (GH-31262)
(cherry picked from commit 0ef0853)
1 parent 1124ab6 commit 8b8673f

File tree

5 files changed

+77
-13
lines changed

5 files changed

+77
-13
lines changed

Lib/test/test_capi.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,6 +1030,22 @@ def test_state_access(self):
10301030
with self.assertRaises(TypeError):
10311031
increment_count(1, 2, 3)
10321032

1033+
def test_get_module_bad_def(self):
1034+
# _PyType_GetModuleByDef fails gracefully if it doesn't
1035+
# find what it's looking for.
1036+
# see bpo-46433
1037+
instance = self.module.StateAccessType()
1038+
with self.assertRaises(TypeError):
1039+
instance.getmodulebydef_bad_def()
1040+
1041+
def test_get_module_static_in_mro(self):
1042+
# Here, the class _PyType_GetModuleByDef is looking for
1043+
# appears in the MRO after a static type (Exception).
1044+
# see bpo-46433
1045+
class Subclass(BaseException, self.module.StateAccessType):
1046+
pass
1047+
self.assertIs(Subclass().get_defining_module(), self.module)
1048+
10331049

10341050
if __name__ == "__main__":
10351051
unittest.main()
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
The internal function _PyType_GetModuleByDef now correctly handles
2+
inheritance patterns involving static types.

Modules/_testmultiphase.c

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ static PyType_Spec Example_Type_spec = {
122122

123123

124124
static PyModuleDef def_meth_state_access;
125+
static PyModuleDef def_nonmodule;
126+
static PyModuleDef def_nonmodule_with_methods;
125127

126128
/*[clinic input]
127129
_testmultiphase.StateAccessType.get_defining_module
@@ -149,6 +151,24 @@ _testmultiphase_StateAccessType_get_defining_module_impl(StateAccessTypeObject *
149151
return retval;
150152
}
151153

154+
/*[clinic input]
155+
_testmultiphase.StateAccessType.getmodulebydef_bad_def
156+
157+
cls: defining_class
158+
159+
Test that result of _PyType_GetModuleByDef with a bad def is NULL.
160+
[clinic start generated code]*/
161+
162+
static PyObject *
163+
_testmultiphase_StateAccessType_getmodulebydef_bad_def_impl(StateAccessTypeObject *self,
164+
PyTypeObject *cls)
165+
/*[clinic end generated code: output=64509074dfcdbd31 input=906047715ee293cd]*/
166+
{
167+
_PyType_GetModuleByDef(Py_TYPE(self), &def_nonmodule); // should raise
168+
assert(PyErr_Occurred());
169+
return NULL;
170+
}
171+
152172
/*[clinic input]
153173
_testmultiphase.StateAccessType.increment_count_clinic
154174
@@ -245,6 +265,7 @@ _testmultiphase_StateAccessType_get_count_impl(StateAccessTypeObject *self,
245265

246266
static PyMethodDef StateAccessType_methods[] = {
247267
_TESTMULTIPHASE_STATEACCESSTYPE_GET_DEFINING_MODULE_METHODDEF
268+
_TESTMULTIPHASE_STATEACCESSTYPE_GETMODULEBYDEF_BAD_DEF_METHODDEF
248269
_TESTMULTIPHASE_STATEACCESSTYPE_GET_COUNT_METHODDEF
249270
_TESTMULTIPHASE_STATEACCESSTYPE_INCREMENT_COUNT_CLINIC_METHODDEF
250271
{
@@ -433,9 +454,6 @@ PyInit__testmultiphase(PyObject *spec)
433454

434455
/**** Importing a non-module object ****/
435456

436-
static PyModuleDef def_nonmodule;
437-
static PyModuleDef def_nonmodule_with_methods;
438-
439457
/* Create a SimpleNamespace(three=3) */
440458
static PyObject*
441459
createfunc_nonmodule(PyObject *spec, PyModuleDef *def)

Modules/clinic/_testmultiphase.c.h

Lines changed: 31 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Objects/typeobject.c

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3707,22 +3707,20 @@ _PyType_GetModuleByDef(PyTypeObject *type, struct PyModuleDef *def)
37073707
// to check i < PyTuple_GET_SIZE(mro) at the first loop iteration.
37083708
assert(PyTuple_GET_SIZE(mro) >= 1);
37093709

3710-
Py_ssize_t i = 0;
3711-
do {
3710+
Py_ssize_t n = PyTuple_GET_SIZE(mro);
3711+
for (Py_ssize_t i = 0; i < n; i++) {
37123712
PyObject *super = PyTuple_GET_ITEM(mro, i);
3713-
// _PyType_GetModuleByDef() must only be called on a heap type created
3714-
// by PyType_FromModuleAndSpec() or on its subclasses.
3715-
// type_ready_mro() ensures that a static type cannot inherit from a
3716-
// heap type.
3717-
assert(_PyType_HasFeature((PyTypeObject *)type, Py_TPFLAGS_HEAPTYPE));
3713+
if(!_PyType_HasFeature((PyTypeObject *)super, Py_TPFLAGS_HEAPTYPE)) {
3714+
// Static types in the MRO need to be skipped
3715+
continue;
3716+
}
37183717

37193718
PyHeapTypeObject *ht = (PyHeapTypeObject*)super;
37203719
PyObject *module = ht->ht_module;
37213720
if (module && _PyModule_GetDef(module) == def) {
37223721
return module;
37233722
}
3724-
i++;
3725-
} while (i < PyTuple_GET_SIZE(mro));
3723+
}
37263724

37273725
PyErr_Format(
37283726
PyExc_TypeError,

0 commit comments

Comments
 (0)