bpo-43916: Add Py_TPFLAGS_DISALLOW_INSTANTIATION type flag (GH-25721)

Add a new Py_TPFLAGS_DISALLOW_INSTANTIATION type flag to disallow
creating type instances: set tp_new to NULL and don't create the
"__new__" key in the type dictionary.

The flag is set automatically on static types if tp_base is NULL or
&PyBaseObject_Type and tp_new is NULL.

Use the flag on the following types:

* _curses.ncurses_version type
* _curses_panel.panel
* _tkinter.Tcl_Obj
* _tkinter.tkapp
* _tkinter.tktimertoken
* _xxsubinterpretersmodule.ChannelID
* sys.flags type
* sys.getwindowsversion() type
* sys.version_info type

Update MyStr example in the C API documentation to use
Py_TPFLAGS_DISALLOW_INSTANTIATION.

Add _PyStructSequence_InitType() function to create a structseq type
with the Py_TPFLAGS_DISALLOW_INSTANTIATION flag set.

type_new() calls _PyType_CheckConsistency() at exit.
This commit is contained in:
Victor Stinner 2021-04-30 12:46:15 +02:00 committed by GitHub
parent b73b5fb9ea
commit 3bb09947ec
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 144 additions and 102 deletions

View file

@ -2810,56 +2810,35 @@ _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,
Py_TPFLAGS_DISALLOW_INSTANTIATION) < 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,
Py_TPFLAGS_DISALLOW_INSTANTIATION) < 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 (WindowsVersionType.tp_name == 0) {
if (_PyStructSequence_InitType(&WindowsVersionType,
&windows_version_desc,
Py_TPFLAGS_DISALLOW_INSTANTIATION) < 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