diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index 9dfc8c62babadb..a6f92f92879bd1 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -178,6 +178,8 @@ extern int _Py_CheckSlotResult( // See also the Py_TPFLAGS_READY flag. #define _PyType_IsReady(type) ((type)->tp_dict != NULL) +extern int _PyType_Ready(PyTypeObject *type, int disallow_instantiation); + #ifdef __cplusplus } #endif diff --git a/Include/structseq.h b/Include/structseq.h index 8f51c89163a4e1..c8a76eae1887a1 100644 --- a/Include/structseq.h +++ b/Include/structseq.h @@ -27,6 +27,12 @@ PyAPI_FUNC(void) PyStructSequence_InitType(PyTypeObject *type, PyAPI_FUNC(int) PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc); #endif +#ifdef Py_BUILD_CORE +PyAPI_FUNC(int) _PyStructSequence_InitType( + PyTypeObject *type, + PyStructSequence_Desc *desc, + int disallow_instantiation); +#endif PyAPI_FUNC(PyTypeObject*) PyStructSequence_NewType(PyStructSequence_Desc *desc); PyAPI_FUNC(PyObject *) PyStructSequence_New(PyTypeObject* type); diff --git a/Modules/_curses_panel.c b/Modules/_curses_panel.c index 94caf8c93bc8c3..b89db808749aa0 100644 --- a/Modules/_curses_panel.c +++ b/Modules/_curses_panel.c @@ -514,6 +514,7 @@ static PyMethodDef PyCursesPanel_Methods[] = { static PyType_Slot PyCursesPanel_Type_slots[] = { {Py_tp_dealloc, PyCursesPanel_Dealloc}, {Py_tp_methods, PyCursesPanel_Methods}, + {Py_tp_new, NULL}, {0, 0}, }; @@ -656,7 +657,6 @@ _curses_panel_exec(PyObject *mod) if (state->PyCursesPanel_Type == NULL) { return -1; } - ((PyTypeObject *)state->PyCursesPanel_Type)->tp_new = NULL; if (PyModule_AddType(mod, state->PyCursesPanel_Type) < 0) { return -1; diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index d221cf1a92520c..d43163fef23ca9 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -4793,9 +4793,10 @@ PyInit__curses(void) #ifdef NCURSES_VERSION /* ncurses_version */ if (NcursesVersionType.tp_name == NULL) { - if (PyStructSequence_InitType2(&NcursesVersionType, - &ncurses_version_desc) < 0) + if (_PyStructSequence_InitType(&NcursesVersionType, + &ncurses_version_desc, 1) < 0) { return NULL; + } } v = make_ncurses_version(); if (v == NULL) { @@ -4803,15 +4804,6 @@ PyInit__curses(void) } PyDict_SetItemString(d, "ncurses_version", v); Py_DECREF(v); - - /* prevent user from creating new instances */ - NcursesVersionType.tp_init = NULL; - NcursesVersionType.tp_new = NULL; - if (PyDict_DelItemString(NcursesVersionType.tp_dict, "__new__") < 0 && - PyErr_ExceptionMatches(PyExc_KeyError)) - { - PyErr_Clear(); - } #endif /* NCURSES_VERSION */ SetDictInt("ERR", ERR); diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 46d6a6e0954f51..79e594496587fe 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -995,6 +995,7 @@ static PyType_Slot PyTclObject_Type_slots[] = { {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_richcompare, PyTclObject_richcompare}, {Py_tp_getset, PyTclObject_getsetlist}, + {Py_tp_new, NULL}, {0, 0} }; @@ -3287,6 +3288,7 @@ static PyType_Slot Tktt_Type_slots[] = { {Py_tp_dealloc, Tktt_Dealloc}, {Py_tp_repr, Tktt_Repr}, {Py_tp_methods, Tktt_methods}, + {Py_tp_new, NULL}, {0, 0} }; @@ -3341,6 +3343,7 @@ static PyMethodDef Tkapp_methods[] = static PyType_Slot Tkapp_Type_slots[] = { {Py_tp_dealloc, Tkapp_Dealloc}, {Py_tp_methods, Tkapp_methods}, + {Py_tp_new, NULL}, {0, 0} }; @@ -3537,7 +3540,6 @@ PyInit__tkinter(void) Py_DECREF(m); return NULL; } - ((PyTypeObject *)o)->tp_new = NULL; if (PyModule_AddObject(m, "TkappType", o)) { Py_DECREF(o); Py_DECREF(m); @@ -3550,7 +3552,6 @@ PyInit__tkinter(void) Py_DECREF(m); return NULL; } - ((PyTypeObject *)o)->tp_new = NULL; if (PyModule_AddObject(m, "TkttType", o)) { Py_DECREF(o); Py_DECREF(m); @@ -3563,7 +3564,6 @@ PyInit__tkinter(void) Py_DECREF(m); return NULL; } - ((PyTypeObject *)o)->tp_new = NULL; if (PyModule_AddObject(m, "Tcl_Obj", o)) { Py_DECREF(o); Py_DECREF(m); diff --git a/Objects/structseq.c b/Objects/structseq.c index 88e63b658a4205..03ed6415bcb9bc 100644 --- a/Objects/structseq.c +++ b/Objects/structseq.c @@ -460,7 +460,8 @@ initialize_members(PyStructSequence_Desc *desc, PyMemberDef* members, } int -PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc) +_PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc, + int disallow_instantiation) { PyMemberDef *members; Py_ssize_t n_members, n_unnamed_members; @@ -487,7 +488,12 @@ PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc) type->tp_doc = desc->doc; type->tp_base = &PyTuple_Type; type->tp_methods = structseq_methods; - type->tp_new = structseq_new; + if (!disallow_instantiation) { + type->tp_new = structseq_new; + } + else { + type->tp_new = NULL; + } type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC; type->tp_traverse = (traverseproc) structseq_traverse; @@ -500,7 +506,7 @@ PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc) initialize_members(desc, members, n_members); type->tp_members = members; - if (PyType_Ready(type) < 0) { + if (_PyType_Ready(type, disallow_instantiation) < 0) { PyMem_Free(members); return -1; } @@ -516,6 +522,12 @@ PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc) return 0; } +int +PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc) +{ + return _PyStructSequence_InitType(type, desc, 0); +} + void PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc) { diff --git a/Objects/typeobject.c b/Objects/typeobject.c index e1c8be4b815452..e9967e0f778c8d 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -73,6 +73,7 @@ _Py_IDENTIFIER(__weakref__); _Py_IDENTIFIER(builtins); _Py_IDENTIFIER(mro); +// Forward declarations static PyObject * slot_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds); @@ -3287,6 +3288,7 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) char *res_start; short slot_offset, subslot_offset; + int disallow_instantiation = 0; nmembers = weaklistoffset = dictoffset = vectorcalloffset = 0; for (slot = spec->slots; slot->slot; slot++) { if (slot->slot == Py_tp_members) { @@ -3313,6 +3315,9 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) } } } + if (slot->slot == Py_tp_new && slot->pfunc == NULL) { + disallow_instantiation = 1; + } } res = (PyHeapTypeObject*)PyType_GenericAlloc(&PyType_Type, nmembers); @@ -3464,7 +3469,7 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) type->tp_vectorcall_offset = vectorcalloffset; } - if (PyType_Ready(type) < 0) + if (_PyType_Ready(type, disallow_instantiation) < 0) goto fail; if (type->tp_dictoffset) { @@ -5582,39 +5587,24 @@ type_add_getset(PyTypeObject *type) static void inherit_special(PyTypeObject *type, PyTypeObject *base) { - /* Copying tp_traverse and tp_clear is connected to the GC flags */ if (!(type->tp_flags & Py_TPFLAGS_HAVE_GC) && (base->tp_flags & Py_TPFLAGS_HAVE_GC) && - (!type->tp_traverse && !type->tp_clear)) { + (!type->tp_traverse && !type->tp_clear)) + { type->tp_flags |= Py_TPFLAGS_HAVE_GC; - if (type->tp_traverse == NULL) + if (type->tp_traverse == NULL) { type->tp_traverse = base->tp_traverse; - if (type->tp_clear == NULL) + } + if (type->tp_clear == NULL) { type->tp_clear = base->tp_clear; + } } - { - /* The condition below could use some explanation. - It appears that tp_new is not inherited for static types - whose base class is 'object'; this seems to be a precaution - so that old extension types don't suddenly become - callable (object.__new__ wouldn't insure the invariants - that the extension type's own factory function ensures). - Heap types, of course, are under our control, so they do - inherit tp_new; static extension types that specify some - other built-in type as the default also - inherit object.__new__. */ - if (base != &PyBaseObject_Type || - (type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { - if (type->tp_new == NULL) - type->tp_new = base->tp_new; - } - } - if (type->tp_basicsize == 0) + if (type->tp_basicsize == 0) { type->tp_basicsize = base->tp_basicsize; + } /* Copy other non-function slots */ - #define COPYVAL(SLOT) \ if (type->SLOT == 0) { type->SLOT = base->SLOT; } @@ -6089,11 +6079,14 @@ type_ready_inherit_as_structs(PyTypeObject *type, PyTypeObject *base) static int -type_ready_inherit(PyTypeObject *type) +type_ready_inherit(PyTypeObject *type, int disallow_instantiation) { /* Inherit special flags from dominant base */ PyTypeObject *base = type->tp_base; if (base != NULL) { + if (type->tp_new == NULL && !disallow_instantiation) { + type->tp_new = base->tp_new; + } inherit_special(type, base); } @@ -6176,7 +6169,7 @@ type_ready_add_subclasses(PyTypeObject *type) static int -type_ready(PyTypeObject *type) +type_ready(PyTypeObject *type, int disallow_instantiation) { if (type_ready_checks(type) < 0) { return -1; @@ -6201,10 +6194,31 @@ type_ready(PyTypeObject *type) if (type_ready_mro(type) < 0) { return -1; } + + /* The condition below could use some explanation. + + It appears that tp_new is not inherited for static types whose base + class is 'object'; this seems to be a precaution so that old extension + types don't suddenly become callable (object.__new__ wouldn't insure the + invariants that the extension type's own factory function ensures). + + Heap types, of course, are under our control, so they do inherit tp_new; + static extension types that specify some other built-in type as the + default also inherit object.__new__. */ + if (type->tp_new == NULL + && type->tp_base == &PyBaseObject_Type + && !(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) + { + disallow_instantiation = 1; + } + if (disallow_instantiation) { + type->tp_new = NULL; + } + if (type_ready_fill_dict(type) < 0) { return -1; } - if (type_ready_inherit(type) < 0) { + if (type_ready_inherit(type, disallow_instantiation) < 0) { return -1; } if (type_ready_set_hash(type) < 0) { @@ -6213,12 +6227,16 @@ type_ready(PyTypeObject *type) if (type_ready_add_subclasses(type) < 0) { return -1; } + if (disallow_instantiation) { + assert(type->tp_new == NULL); + assert(_PyDict_ContainsId(type->tp_dict, &PyId___new__) == 0); + } return 0; } int -PyType_Ready(PyTypeObject *type) +_PyType_Ready(PyTypeObject *type, int disallow_instantiation) { if (type->tp_flags & Py_TPFLAGS_READY) { assert(_PyType_CheckConsistency(type)); @@ -6234,7 +6252,7 @@ PyType_Ready(PyTypeObject *type) type->tp_flags |= Py_TPFLAGS_IMMUTABLETYPE; } - if (type_ready(type) < 0) { + if (type_ready(type, disallow_instantiation) < 0) { type->tp_flags &= ~Py_TPFLAGS_READYING; return -1; } @@ -6245,6 +6263,12 @@ PyType_Ready(PyTypeObject *type) return 0; } +int +PyType_Ready(PyTypeObject *type) +{ + return _PyType_Ready(type, 0); +} + static int add_subclass(PyTypeObject *base, PyTypeObject *type) diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 911c2d967b010a..aaabd62a349c1f 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -2810,57 +2810,32 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict) /* version_info */ if (VersionInfoType.tp_name == NULL) { - if (PyStructSequence_InitType2(&VersionInfoType, - &version_info_desc) < 0) { + if (_PyStructSequence_InitType(&VersionInfoType, + &version_info_desc, 1) < 0) { goto type_init_failed; } } version_info = make_version_info(tstate); SET_SYS("version_info", version_info); - /* prevent user from creating new instances */ - VersionInfoType.tp_init = NULL; - VersionInfoType.tp_new = NULL; - res = PyDict_DelItemString(VersionInfoType.tp_dict, "__new__"); - if (res < 0 && _PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { - _PyErr_Clear(tstate); - } /* implementation */ SET_SYS("implementation", make_impl_info(version_info)); // sys.flags: updated in-place later by _PySys_UpdateConfig() if (FlagsType.tp_name == 0) { - if (PyStructSequence_InitType2(&FlagsType, &flags_desc) < 0) { + if (_PyStructSequence_InitType(&FlagsType, &flags_desc, 1) < 0) { goto type_init_failed; } } SET_SYS("flags", make_flags(tstate->interp)); - /* prevent user from creating new instances */ - FlagsType.tp_init = NULL; - FlagsType.tp_new = NULL; - res = PyDict_DelItemString(FlagsType.tp_dict, "__new__"); - if (res < 0) { - if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { - goto err_occurred; - } - _PyErr_Clear(tstate); - } #if defined(MS_WINDOWS) /* getwindowsversion */ if (WindowsVersionType.tp_name == 0) - if (PyStructSequence_InitType2(&WindowsVersionType, - &windows_version_desc) < 0) { + if (_PyStructSequence_InitType(&WindowsVersionType, + &windows_version_desc, 1) < 0) { goto type_init_failed; } - /* prevent user from creating new instances */ - WindowsVersionType.tp_init = NULL; - WindowsVersionType.tp_new = NULL; - assert(!_PyErr_Occurred(tstate)); - res = PyDict_DelItemString(WindowsVersionType.tp_dict, "__new__"); - if (res < 0 && _PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { - _PyErr_Clear(tstate); - } #endif /* float repr style: 0.03 (short) vs 0.029999999999999999 (legacy) */