Skip to content

Commit 0ef0853

Browse files
authored
bpo-46433: _PyType_GetModuleByDef: handle static types in MRO (GH-30696)
Automerge-Triggered-By: GH:encukou
1 parent 0d05da1 commit 0ef0853

File tree

5 files changed

+74
-9
lines changed

5 files changed

+74
-9
lines changed

Lib/test/test_capi.py

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

1071+
def test_get_module_bad_def(self):
1072+
# _PyType_GetModuleByDef fails gracefully if it doesn't
1073+
# find what it's looking for.
1074+
# see bpo-46433
1075+
instance = self.module.StateAccessType()
1076+
with self.assertRaises(TypeError):
1077+
instance.getmodulebydef_bad_def()
1078+
1079+
def test_get_module_static_in_mro(self):
1080+
# Here, the class _PyType_GetModuleByDef is looking for
1081+
# appears in the MRO after a static type (Exception).
1082+
# see bpo-46433
1083+
class Subclass(BaseException, self.module.StateAccessType):
1084+
pass
1085+
self.assertIs(Subclass().get_defining_module(), self.module)
1086+
10711087

10721088
if __name__ == "__main__":
10731089
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
@@ -126,6 +126,8 @@ static PyType_Spec Example_Type_spec = {
126126

127127

128128
static PyModuleDef def_meth_state_access;
129+
static PyModuleDef def_nonmodule;
130+
static PyModuleDef def_nonmodule_with_methods;
129131

130132
/*[clinic input]
131133
_testmultiphase.StateAccessType.get_defining_module
@@ -153,6 +155,24 @@ _testmultiphase_StateAccessType_get_defining_module_impl(StateAccessTypeObject *
153155
return retval;
154156
}
155157

158+
/*[clinic input]
159+
_testmultiphase.StateAccessType.getmodulebydef_bad_def
160+
161+
cls: defining_class
162+
163+
Test that result of _PyType_GetModuleByDef with a bad def is NULL.
164+
[clinic start generated code]*/
165+
166+
static PyObject *
167+
_testmultiphase_StateAccessType_getmodulebydef_bad_def_impl(StateAccessTypeObject *self,
168+
PyTypeObject *cls)
169+
/*[clinic end generated code: output=64509074dfcdbd31 input=906047715ee293cd]*/
170+
{
171+
_PyType_GetModuleByDef(Py_TYPE(self), &def_nonmodule); // should raise
172+
assert(PyErr_Occurred());
173+
return NULL;
174+
}
175+
156176
/*[clinic input]
157177
_testmultiphase.StateAccessType.increment_count_clinic
158178
@@ -249,6 +269,7 @@ _testmultiphase_StateAccessType_get_count_impl(StateAccessTypeObject *self,
249269

250270
static PyMethodDef StateAccessType_methods[] = {
251271
_TESTMULTIPHASE_STATEACCESSTYPE_GET_DEFINING_MODULE_METHODDEF
272+
_TESTMULTIPHASE_STATEACCESSTYPE_GETMODULEBYDEF_BAD_DEF_METHODDEF
252273
_TESTMULTIPHASE_STATEACCESSTYPE_GET_COUNT_METHODDEF
253274
_TESTMULTIPHASE_STATEACCESSTYPE_INCREMENT_COUNT_CLINIC_METHODDEF
254275
{
@@ -437,9 +458,6 @@ PyInit__testmultiphase(PyObject *spec)
437458

438459
/**** Importing a non-module object ****/
439460

440-
static PyModuleDef def_nonmodule;
441-
static PyModuleDef def_nonmodule_with_methods;
442-
443461
/* Create a SimpleNamespace(three=3) */
444462
static PyObject*
445463
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: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3756,11 +3756,10 @@ _PyType_GetModuleByDef(PyTypeObject *type, struct PyModuleDef *def)
37563756
Py_ssize_t n = PyTuple_GET_SIZE(mro);
37573757
for (Py_ssize_t i = 0; i < n; i++) {
37583758
PyObject *super = PyTuple_GET_ITEM(mro, i);
3759-
// _PyType_GetModuleByDef() must only be called on a heap type created
3760-
// by PyType_FromModuleAndSpec() or on its subclasses.
3761-
// type_ready_mro() ensures that a static type cannot inherit from a
3762-
// heap type.
3763-
assert(_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE));
3759+
if(!_PyType_HasFeature((PyTypeObject *)super, Py_TPFLAGS_HEAPTYPE)) {
3760+
// Static types in the MRO need to be skipped
3761+
continue;
3762+
}
37643763

37653764
PyHeapTypeObject *ht = (PyHeapTypeObject*)super;
37663765
PyObject *module = ht->ht_module;

0 commit comments

Comments
 (0)