summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Include/internal/pycore_typeobject.h1
-rw-r--r--Lib/test/test_types.py36
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2024-07-10-15-43-54.gh-issue-117482.5WYaXR.rst2
-rw-r--r--Objects/typeobject.c40
4 files changed, 69 insertions, 10 deletions
diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h
index 32bd19d..df6bfef 100644
--- a/Include/internal/pycore_typeobject.h
+++ b/Include/internal/pycore_typeobject.h
@@ -33,6 +33,7 @@ struct _types_runtime_state {
struct {
struct {
PyTypeObject *type;
+ PyTypeObject def;
int64_t interp_count;
} types[_Py_MAX_MANAGED_STATIC_TYPES];
} managed_static;
diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py
index fbca198..38a9882 100644
--- a/Lib/test/test_types.py
+++ b/Lib/test/test_types.py
@@ -10,6 +10,7 @@ import inspect
import pickle
import locale
import sys
+import textwrap
import types
import unittest.mock
import weakref
@@ -2345,5 +2346,40 @@ class FunctionTests(unittest.TestCase):
)
+class SubinterpreterTests(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ global interpreters
+ try:
+ from test.support import interpreters
+ except ModuleNotFoundError:
+ raise unittest.SkipTest('subinterpreters required')
+ import test.support.interpreters.channels
+
+ @cpython_only
+ def test_slot_wrappers(self):
+ rch, sch = interpreters.channels.create()
+
+ # For now it's sufficient to check int.__str__.
+ # See https://github.com/python/cpython/issues/117482
+ # and https://github.com/python/cpython/pull/117660.
+ script = textwrap.dedent('''
+ text = repr(int.__str__)
+ sch.send_nowait(text)
+ ''')
+
+ exec(script)
+ expected = rch.recv()
+
+ interp = interpreters.create()
+ interp.exec('from test.support import interpreters')
+ interp.prepare_main(sch=sch)
+ interp.exec(script)
+ results = rch.recv()
+
+ self.assertEqual(results, expected)
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-07-10-15-43-54.gh-issue-117482.5WYaXR.rst b/Misc/NEWS.d/next/Core and Builtins/2024-07-10-15-43-54.gh-issue-117482.5WYaXR.rst
new file mode 100644
index 0000000..ec1e732
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2024-07-10-15-43-54.gh-issue-117482.5WYaXR.rst
@@ -0,0 +1,2 @@
+Unexpected slot wrappers are no longer created for builtin static types in
+subinterpreters.
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 587632c..7d01b68 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -314,6 +314,16 @@ managed_static_type_state_clear(PyInterpreterState *interp, PyTypeObject *self,
}
}
+static PyTypeObject *
+managed_static_type_get_def(PyTypeObject *self, int isbuiltin)
+{
+ size_t index = managed_static_type_index_get(self);
+ size_t full_index = isbuiltin
+ ? index
+ : index + _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES;
+ return &_PyRuntime.types.managed_static.types[full_index].def;
+}
+
// Also see _PyStaticType_InitBuiltin() and _PyStaticType_FiniBuiltin().
/* end static builtin helpers */
@@ -5840,7 +5850,6 @@ fini_static_type(PyInterpreterState *interp, PyTypeObject *type,
_PyStaticType_ClearWeakRefs(interp, type);
managed_static_type_state_clear(interp, type, isbuiltin, final);
- /* We leave _Py_TPFLAGS_STATIC_BUILTIN set on tp_flags. */
}
void
@@ -7850,7 +7859,7 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base)
return 0;
}
-static int add_operators(PyTypeObject *);
+static int add_operators(PyTypeObject *, PyTypeObject *);
static int add_tp_new_wrapper(PyTypeObject *type);
#define COLLECTION_FLAGS (Py_TPFLAGS_SEQUENCE | Py_TPFLAGS_MAPPING)
@@ -8015,10 +8024,10 @@ type_dict_set_doc(PyTypeObject *type)
static int
-type_ready_fill_dict(PyTypeObject *type)
+type_ready_fill_dict(PyTypeObject *type, PyTypeObject *def)
{
/* Add type-specific descriptors to tp_dict */
- if (add_operators(type) < 0) {
+ if (add_operators(type, def) < 0) {
return -1;
}
if (type_add_methods(type) < 0) {
@@ -8337,7 +8346,7 @@ type_ready_post_checks(PyTypeObject *type)
static int
-type_ready(PyTypeObject *type, int initial)
+type_ready(PyTypeObject *type, PyTypeObject *def, int initial)
{
ASSERT_TYPE_LOCK_HELD();
@@ -8376,7 +8385,7 @@ type_ready(PyTypeObject *type, int initial)
if (type_ready_set_new(type, initial) < 0) {
goto error;
}
- if (type_ready_fill_dict(type) < 0) {
+ if (type_ready_fill_dict(type, def) < 0) {
goto error;
}
if (initial) {
@@ -8433,7 +8442,7 @@ PyType_Ready(PyTypeObject *type)
int res;
BEGIN_TYPE_LOCK();
if (!(type->tp_flags & Py_TPFLAGS_READY)) {
- res = type_ready(type, 1);
+ res = type_ready(type, NULL, 1);
} else {
res = 0;
assert(_PyType_CheckConsistency(type));
@@ -8469,14 +8478,20 @@ init_static_type(PyInterpreterState *interp, PyTypeObject *self,
managed_static_type_state_init(interp, self, isbuiltin, initial);
+ PyTypeObject *def = managed_static_type_get_def(self, isbuiltin);
+ if (initial) {
+ memcpy(def, self, sizeof(PyTypeObject));
+ }
+
int res;
BEGIN_TYPE_LOCK();
- res = type_ready(self, initial);
+ res = type_ready(self, def, initial);
END_TYPE_LOCK();
if (res < 0) {
_PyStaticType_ClearWeakRefs(interp, self);
managed_static_type_state_clear(interp, self, isbuiltin, initial);
}
+
return res;
}
@@ -11064,17 +11079,22 @@ recurse_down_subclasses(PyTypeObject *type, PyObject *attr_name,
infinite recursion here.) */
static int
-add_operators(PyTypeObject *type)
+add_operators(PyTypeObject *type, PyTypeObject *def)
{
PyObject *dict = lookup_tp_dict(type);
pytype_slotdef *p;
PyObject *descr;
void **ptr;
+ assert(def == NULL || (type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN));
+ if (def == NULL) {
+ def = type;
+ }
+
for (p = slotdefs; p->name; p++) {
if (p->wrapper == NULL)
continue;
- ptr = slotptr(type, p->offset);
+ ptr = slotptr(def, p->offset);
if (!ptr || !*ptr)
continue;
int r = PyDict_Contains(dict, p->name_strobj);