Skip to content
Open
9 changes: 9 additions & 0 deletions Lib/test/test_descr.py
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,15 @@ class X(C, int()):
class X(int(), C):
pass

@unittest.skipIf(_testcapi is None, 'need the _testcapi module')
def test_type_with_null_new_metaclass(self):
metaclass = _testcapi.HeapCTypeMetaclassNullNew
base = _testcapi.pytype_fromspec_meta(metaclass)

# Exercise type_new's metaclass selection path, not a direct call.
with self.assertRaisesRegex(TypeError, r"cannot create '.*' instances"):
type("Derived", (base,), {})

def test_module_subclasses(self):
# Testing Python subclass of module...
log = []
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed a crash in ``type()`` when selecting a metaclass whose ``tp_new`` slot is ``NULL``. Such metaclasses are now rejected with ``TypeError`` instead of causing a NULL pointer dereference.
7 changes: 7 additions & 0 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -5031,6 +5031,13 @@ type_new_get_bases(type_new_ctx *ctx, PyObject **type)

if (winner != ctx->metatype) {
if (winner->tp_new != type_new) {
/* Check if tp_new is NULL (cannot instantiate this type) */
if (winner->tp_new == NULL) {
PyErr_Format(PyExc_TypeError,
"cannot create '%.400s' instances",
winner->tp_name);
return -1;
}
/* Pass it to the winner */
*type = winner->tp_new(winner, ctx->args, ctx->kwds);
if (*type == NULL) {
Comment on lines +5034 to 5043
Expand Down
Loading