summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorEric Snow <ericsnowcurrently@gmail.com>2023-06-01 22:28:31 (GMT)
committerGitHub <noreply@github.com>2023-06-01 22:28:31 (GMT)
commit146939306adcff706ebddb047f7470d148125cdf (patch)
tree7ba1a0832da33fff49813d51dee801e54efd9fce /Lib
parent3698fda06eefb3c01e78c4c07f46fcdd0559e0f6 (diff)
downloadcpython-146939306adcff706ebddb047f7470d148125cdf.zip
cpython-146939306adcff706ebddb047f7470d148125cdf.tar.gz
cpython-146939306adcff706ebddb047f7470d148125cdf.tar.bz2
gh-104614: Make Sure ob_type is Always Set Correctly by PyType_Ready() (gh-105122)
When I added the relevant condition to type_ready_set_bases() in gh-103912, I had missed that the function also sets tp_base and ob_type (if necessary). That led to problems for third-party static types. We fix that here, by making those extra operations distinct and by adjusting the condition to be more specific.
Diffstat (limited to 'Lib')
-rw-r--r--Lib/test/test_capi/test_misc.py38
1 files changed, 37 insertions, 1 deletions
diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py
index 037c811..e1b55cf 100644
--- a/Lib/test/test_capi/test_misc.py
+++ b/Lib/test/test_capi/test_misc.py
@@ -1,8 +1,9 @@
# Run the _testcapi module tests (tests for the Python/C API): by defn,
# these are all functions _testcapi exports whose name begins with 'test_'.
-from collections import OrderedDict
import _thread
+from collections import OrderedDict
+import contextlib
import importlib.machinery
import importlib.util
import os
@@ -1626,6 +1627,41 @@ class BuiltinStaticTypesTests(unittest.TestCase):
self.assertIsNot(mro, None)
+class TestStaticTypes(unittest.TestCase):
+
+ _has_run = False
+
+ @classmethod
+ def setUpClass(cls):
+ # The tests here don't play nice with our approach to refleak
+ # detection, so we bail out in that case.
+ if cls._has_run:
+ raise unittest.SkipTest('these tests do not support re-running')
+ cls._has_run = True
+
+ @contextlib.contextmanager
+ def basic_static_type(self, *args):
+ cls = _testcapi.get_basic_static_type(*args)
+ yield cls
+
+ def test_pytype_ready_always_sets_tp_type(self):
+ # The point of this test is to prevent something like
+ # https://github.com/python/cpython/issues/104614
+ # from happening again.
+
+ # First check when tp_base/tp_bases is *not* set before PyType_Ready().
+ with self.basic_static_type() as cls:
+ self.assertIs(cls.__base__, object);
+ self.assertEqual(cls.__bases__, (object,));
+ self.assertIs(type(cls), type(object));
+
+ # Then check when we *do* set tp_base/tp_bases first.
+ with self.basic_static_type(object) as cls:
+ self.assertIs(cls.__base__, object);
+ self.assertEqual(cls.__bases__, (object,));
+ self.assertIs(type(cls), type(object));
+
+
class TestThreadState(unittest.TestCase):
@threading_helper.reap_threads