From 9746cda705decebc0ba572d95612796afd06dcd4 Mon Sep 17 00:00:00 2001 From: Erlend Egeberg Aasland Date: Fri, 30 Apr 2021 16:04:57 +0200 Subject: [PATCH] bpo-43916: Apply Py_TPFLAGS_DISALLOW_INSTANTIATION to selected types (GH-25748) Apply Py_TPFLAGS_DISALLOW_INSTANTIATION to the following types: * _dbm.dbm * _gdbm.gdbm * _multibytecodec.MultibyteCodec * _sre..SRE_Scanner * _thread._localdummy * _thread.lock * _winapi.Overlapped * array.arrayiterator * functools.KeyWrapper * functools._lru_list_elem * pyexpat.xmlparser * re.Match * re.Pattern * unicodedata.UCD * zlib.Compress * zlib.Decompress --- Lib/test/test_array.py | 6 ++++++ Lib/test/test_curses.py | 6 ++++-- Lib/test/test_dbm_gnu.py | 9 ++++++++- Lib/test/test_functools.py | 6 ++++++ Lib/test/test_re.py | 9 +++++++++ Lib/test/test_tcl.py | 3 +++ Lib/test/test_threading.py | 7 +++++++ Lib/test/test_unicodedata.py | 8 +++++++- Lib/test/test_zlib.py | 8 ++++++++ Modules/_dbmmodule.c | 2 +- Modules/_functoolsmodule.c | 4 ++-- Modules/_gdbmmodule.c | 2 +- Modules/_sre.c | 9 ++++++--- Modules/_threadmodule.c | 5 +++-- Modules/_winapi.c | 2 +- Modules/arraymodule.c | 3 ++- Modules/cjkcodecs/multibytecodec.c | 3 ++- Modules/pyexpat.c | 3 ++- Modules/unicodedata.c | 2 +- Modules/zlibmodule.c | 18 ++++++++---------- 20 files changed, 87 insertions(+), 28 deletions(-) diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py index 11184add6d3..b18467fb889 100644 --- a/Lib/test/test_array.py +++ b/Lib/test/test_array.py @@ -40,6 +40,12 @@ class MiscTest(unittest.TestCase): self.assertRaises(TypeError, array.array, 'xx') self.assertRaises(ValueError, array.array, 'x') + @support.cpython_only + def test_disallow_instantiation(self): + # Ensure that the type disallows instantiation (bpo-43916) + tp = type(iter(array.array('I'))) + self.assertRaises(TypeError, tp) + @support.cpython_only def test_immutable(self): # bpo-43908: check that array.array is immutable diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index 280a9dc0eed..8bf48a6454d 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -6,7 +6,7 @@ import sys import tempfile import unittest -from test.support import requires, verbose, SaveSignals +from test.support import requires, verbose, SaveSignals, cpython_only from test.support.import_helper import import_module # Optionally test curses module. This currently requires that the @@ -1046,8 +1046,10 @@ class TestCurses(unittest.TestCase): panel.set_userptr(A()) panel.set_userptr(None) + @cpython_only @requires_curses_func('panel') - def test_new_curses_panel(self): + def test_disallow_instantiation(self): + # Ensure that the type disallows instantiation (bpo-43916) w = curses.newwin(10, 10) panel = curses.panel.new_panel(w) self.assertRaises(TypeError, type(panel)) diff --git a/Lib/test/test_dbm_gnu.py b/Lib/test/test_dbm_gnu.py index 017d0ffa658..b3e55728c8e 100644 --- a/Lib/test/test_dbm_gnu.py +++ b/Lib/test/test_dbm_gnu.py @@ -1,5 +1,5 @@ from test import support -from test.support import import_helper +from test.support import import_helper, cpython_only gdbm = import_helper.import_module("dbm.gnu") #skip if not supported import unittest import os @@ -27,6 +27,13 @@ class TestGdbm(unittest.TestCase): self.g.close() unlink(filename) + @cpython_only + def test_disallow_instantiation(self): + # Ensure that the type disallows instantiation (bpo-43916) + self.g = gdbm.open(filename, 'c') + tp = type(self.g) + self.assertRaises(TypeError, tp) + def test_key_methods(self): self.g = gdbm.open(filename, 'c') self.assertEqual(self.g.keys(), []) diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py index fba9281deb3..3320ab7ec66 100644 --- a/Lib/test/test_functools.py +++ b/Lib/test/test_functools.py @@ -948,6 +948,12 @@ class TestCmpToKeyC(TestCmpToKey, unittest.TestCase): if c_functools: cmp_to_key = c_functools.cmp_to_key + @support.cpython_only + def test_disallow_instantiation(self): + # Ensure that the type disallows instantiation (bpo-43916) + tp = type(c_functools.cmp_to_key(None)) + self.assertRaises(TypeError, tp) + class TestCmpToKeyPy(TestCmpToKey, unittest.TestCase): cmp_to_key = staticmethod(py_functools.cmp_to_key) diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py index 96d0cdb17a7..e1b2c794291 100644 --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -2215,6 +2215,15 @@ class ImplementationTest(unittest.TestCase): self.assertGreaterEqual(sre_compile.MAXREPEAT, 0) self.assertGreaterEqual(sre_compile.MAXGROUPS, 0) + @cpython_only + def test_disallow_instantiation(self): + # Ensure that the type disallows instantiation (bpo-43916) + self.assertRaises(TypeError, re.Match) + self.assertRaises(TypeError, re.Pattern) + pat = re.compile("") + tp = type(pat.scanner("")) + self.assertRaises(TypeError, tp) + class ExternalTests(unittest.TestCase): diff --git a/Lib/test/test_tcl.py b/Lib/test/test_tcl.py index ee7344c48ed..cd3aacf6f88 100644 --- a/Lib/test/test_tcl.py +++ b/Lib/test/test_tcl.py @@ -736,8 +736,11 @@ class TclTest(unittest.TestCase): check('{\n') check('}\n') + @support.cpython_only def test_new_tcl_obj(self): self.assertRaises(TypeError, _tkinter.Tcl_Obj) + self.assertRaises(TypeError, _tkinter.TkttType) + self.assertRaises(TypeError, _tkinter.TkappType) class BigmemTclTest(unittest.TestCase): diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index f44f17f2978..546773e3329 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -119,6 +119,13 @@ class ThreadTests(BaseTestCase): thread = threading.Thread(target=func) self.assertEqual(thread.name, "Thread-5 (func)") + @cpython_only + def test_disallow_instantiation(self): + # Ensure that the type disallows instantiation (bpo-43916) + lock = threading.Lock() + tp = type(lock) + self.assertRaises(TypeError, tp) + # Create a bunch of threads, let each do some work, wait until all are # done. def test_various_ops(self): diff --git a/Lib/test/test_unicodedata.py b/Lib/test/test_unicodedata.py index edfd860fd5f..c6bbe3f5ff2 100644 --- a/Lib/test/test_unicodedata.py +++ b/Lib/test/test_unicodedata.py @@ -11,7 +11,8 @@ from http.client import HTTPException import sys import unicodedata import unittest -from test.support import open_urlresource, requires_resource, script_helper +from test.support import (open_urlresource, requires_resource, script_helper, + cpython_only) class UnicodeMethodsTest(unittest.TestCase): @@ -225,6 +226,11 @@ class UnicodeFunctionsTest(UnicodeDatabaseTest): class UnicodeMiscTest(UnicodeDatabaseTest): + @cpython_only + def test_disallow_instantiation(self): + # Ensure that the type disallows instantiation (bpo-43916) + self.assertRaises(TypeError, unicodedata.UCD) + def test_failed_import_during_compiling(self): # Issue 4367 # Decoding \N escapes requires the unicodedata module. If it can't be diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py index 7f30cac64f7..694ef6e4875 100644 --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -129,6 +129,14 @@ class ExceptionTestCase(unittest.TestCase): with self.assertRaisesRegex(OverflowError, 'int too large'): zlib.decompressobj().flush(sys.maxsize + 1) + @support.cpython_only + def test_disallow_instantiation(self): + # Ensure that the type disallows instantiation (bpo-43916) + comp_type = type(zlib.compressobj()) + decomp_type = type(zlib.decompressobj()) + self.assertRaises(TypeError, comp_type) + self.assertRaises(TypeError, decomp_type) + class BaseCompressTestCase(object): def check_big_compress_buffer(self, size, compress_func): diff --git a/Modules/_dbmmodule.c b/Modules/_dbmmodule.c index 97772a04d08..58f9c2c357b 100644 --- a/Modules/_dbmmodule.c +++ b/Modules/_dbmmodule.c @@ -414,7 +414,7 @@ static PyType_Spec dbmtype_spec = { // dbmtype_spec does not have Py_TPFLAGS_BASETYPE flag // which prevents to create a subclass. // So calling PyType_GetModuleState() in this file is always safe. - .flags = Py_TPFLAGS_DEFAULT, + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, .slots = dbmtype_spec_slots, }; diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c index eea542e18c9..19cfa9b07b3 100644 --- a/Modules/_functoolsmodule.c +++ b/Modules/_functoolsmodule.c @@ -546,7 +546,7 @@ static PyType_Slot keyobject_type_slots[] = { static PyType_Spec keyobject_type_spec = { .name = "functools.KeyWrapper", .basicsize = sizeof(keyobject), - .flags = Py_TPFLAGS_DEFAULT, + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, .slots = keyobject_type_slots }; @@ -766,7 +766,7 @@ static PyType_Slot lru_list_elem_type_slots[] = { static PyType_Spec lru_list_elem_type_spec = { .name = "functools._lru_list_elem", .basicsize = sizeof(lru_list_elem), - .flags = Py_TPFLAGS_DEFAULT, + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, .slots = lru_list_elem_type_slots }; diff --git a/Modules/_gdbmmodule.c b/Modules/_gdbmmodule.c index 9e843acbaa6..c52190a7ed2 100644 --- a/Modules/_gdbmmodule.c +++ b/Modules/_gdbmmodule.c @@ -570,7 +570,7 @@ static PyType_Spec gdbmtype_spec = { // dbmtype_spec does not have Py_TPFLAGS_BASETYPE flag // which prevents to create a subclass. // So calling PyType_GetModuleState() in this file is always safe. - .flags = Py_TPFLAGS_DEFAULT, + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, .slots = gdbmtype_spec_slots, }; diff --git a/Modules/_sre.c b/Modules/_sre.c index 59f7551a227..9d0fc4ab7c0 100644 --- a/Modules/_sre.c +++ b/Modules/_sre.c @@ -2690,7 +2690,8 @@ static PyType_Spec pattern_spec = { .name = "re.Pattern", .basicsize = sizeof(PatternObject), .itemsize = sizeof(SRE_CODE), - .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE, + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE | + Py_TPFLAGS_DISALLOW_INSTANTIATION), .slots = pattern_slots, }; @@ -2755,7 +2756,8 @@ static PyType_Spec match_spec = { .name = "re.Match", .basicsize = sizeof(MatchObject), .itemsize = sizeof(Py_ssize_t), - .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE, + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE | + Py_TPFLAGS_DISALLOW_INSTANTIATION), .slots = match_slots, }; @@ -2781,7 +2783,8 @@ static PyType_Slot scanner_slots[] = { static PyType_Spec scanner_spec = { .name = "_" SRE_MODULE ".SRE_Scanner", .basicsize = sizeof(ScannerObject), - .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE, + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE | + Py_TPFLAGS_DISALLOW_INSTANTIATION), .slots = scanner_slots, }; diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index 7feb0b8a1f1..6924d6553a1 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -312,7 +312,8 @@ static PyType_Slot lock_type_slots[] = { static PyType_Spec lock_type_spec = { .name = "_thread.lock", .basicsize = sizeof(lockobject), - .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_DISALLOW_INSTANTIATION), .slots = lock_type_slots, }; @@ -683,7 +684,7 @@ static PyType_Slot local_dummy_type_slots[] = { static PyType_Spec local_dummy_type_spec = { .name = "_thread._localdummy", .basicsize = sizeof(localdummyobject), - .flags = Py_TPFLAGS_DEFAULT, + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, .slots = local_dummy_type_slots, }; diff --git a/Modules/_winapi.c b/Modules/_winapi.c index 9d5a45adac5..bc2126c8e2e 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -331,7 +331,7 @@ static PyType_Slot winapi_overlapped_type_slots[] = { static PyType_Spec winapi_overlapped_type_spec = { .name = "_winapi.Overlapped", .basicsize = sizeof(OverlappedObject), - .flags = Py_TPFLAGS_DEFAULT, + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, .slots = winapi_overlapped_type_slots, }; diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index d65c1449eb3..aa5886f4af7 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -2987,7 +2987,8 @@ static PyType_Slot arrayiter_slots[] = { static PyType_Spec arrayiter_spec = { .name = "array.arrayiterator", .basicsize = sizeof(arrayiterobject), - .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_DISALLOW_INSTANTIATION), .slots = arrayiter_slots, }; diff --git a/Modules/cjkcodecs/multibytecodec.c b/Modules/cjkcodecs/multibytecodec.c index 5070c983d40..cb7182ff21f 100644 --- a/Modules/cjkcodecs/multibytecodec.c +++ b/Modules/cjkcodecs/multibytecodec.c @@ -748,7 +748,8 @@ static PyType_Slot multibytecodec_slots[] = { static PyType_Spec multibytecodec_spec = { .name = MODULE_NAME ".MultibyteCodec", .basicsize = sizeof(MultibyteCodecObject), - .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_DISALLOW_INSTANTIATION), .slots = multibytecodec_slots, }; diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c index a13d340a3ea..7f727a86f5f 100644 --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -1506,7 +1506,8 @@ static PyType_Slot _xml_parse_type_spec_slots[] = { static PyType_Spec _xml_parse_type_spec = { .name = "pyexpat.xmlparser", .basicsize = sizeof(xmlparseobject), - .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_DISALLOW_INSTANTIATION), .slots = _xml_parse_type_spec_slots, }; diff --git a/Modules/unicodedata.c b/Modules/unicodedata.c index aebae7da576..1a41e1c2c52 100644 --- a/Modules/unicodedata.c +++ b/Modules/unicodedata.c @@ -1454,7 +1454,7 @@ static PyType_Slot ucd_type_slots[] = { static PyType_Spec ucd_type_spec = { .name = "unicodedata.UCD", .basicsize = sizeof(PreviousDBVersion), - .flags = Py_TPFLAGS_DEFAULT, + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, .slots = ucd_type_slots }; diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c index 8a20dfcbf9e..fc63ca9445a 100644 --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -1386,11 +1386,10 @@ static PyType_Slot Comptype_slots[] = { }; static PyType_Spec Comptype_spec = { - "zlib.Compress", - sizeof(compobject), - 0, - Py_TPFLAGS_DEFAULT, - Comptype_slots + .name = "zlib.Compress", + .basicsize = sizeof(compobject), + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, + .slots= Comptype_slots, }; static PyType_Slot Decomptype_slots[] = { @@ -1401,11 +1400,10 @@ static PyType_Slot Decomptype_slots[] = { }; static PyType_Spec Decomptype_spec = { - "zlib.Decompress", - sizeof(compobject), - 0, - Py_TPFLAGS_DEFAULT, - Decomptype_slots + .name = "zlib.Decompress", + .basicsize = sizeof(compobject), + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, + .slots = Decomptype_slots, }; PyDoc_STRVAR(zlib_module_documentation,