]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-146587: fix type slot assignment incase of multiple slots for same name (#146593)
authorKumar Aditya <kumaraditya@python.org>
Mon, 30 Mar 2026 12:37:38 +0000 (18:07 +0530)
committerGitHub <noreply@github.com>
Mon, 30 Mar 2026 12:37:38 +0000 (18:07 +0530)
Lib/test/test_descr.py
Misc/NEWS.d/next/Core_and_Builtins/2026-03-29-11-39-05.gh-issue-146587.YJicXt.rst [new file with mode: 0644]
Objects/typeobject.c
Tools/c-analyzer/cpython/ignored.tsv

index d6e3719479a214731d5f70b02983a88aff28a220..1d7669e4fa5c968208e69f175fcbabf734b67726 100644 (file)
@@ -5361,6 +5361,31 @@ class ClassPropertiesAndMethods(unittest.TestCase):
         with self.assertRaisesRegex(NotImplementedError, "BAR"):
             B().foo
 
+    def test_gh146587(self):
+        # See https://github.com/python/cpython/issues/146587
+
+        class A:
+            def __radd__(self, other): ...
+
+        class B(tuple): ...
+
+        self.assertIsNone(() + A())
+        self.assertIsNone(B() + A())
+
+        from typing import NamedTuple
+
+        class T(NamedTuple):
+            x: int
+
+        class A:
+            def __init__(self, *args):
+                self.lst = list(args)
+            def __radd__(self, other):
+                return A(*self.lst, other)
+
+        self.assertEqual(((1,)+A()).lst, [(1,)])
+        self.assertEqual((T(x=1)+A()).lst, [T(x=1)])
+
 
 class DictProxyTests(unittest.TestCase):
     def setUp(self):
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-03-29-11-39-05.gh-issue-146587.YJicXt.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-03-29-11-39-05.gh-issue-146587.YJicXt.rst
new file mode 100644 (file)
index 0000000..a33dee5
--- /dev/null
@@ -0,0 +1 @@
+Fix type slot assignment incase of multiple slots for same name in type object implementation. Patch by Kumar Aditya.
index 3374051c42af8a7f944e55d547498e08012684b2..6ceeb7dda08e9f019e87a5b8daf78e4155beaa9c 100644 (file)
@@ -11601,7 +11601,7 @@ static pytype_slotdef slotdefs[] = {
 /* Stores the number of times where slotdefs has elements with same name.
    This counter precalculated by _PyType_InitSlotDefs() when the main
    interpreter starts. */
-static uint8_t slotdefs_name_counts[Py_ARRAY_LENGTH(slotdefs)];
+static uint8_t slotdefs_dups[Py_ARRAY_LENGTH(slotdefs)][1 + MAX_EQUIV];
 
 /* Given a type pointer and an offset gotten from a slotdef entry, return a
    pointer to the actual slot.  This is not quite the same as simply adding
@@ -11768,11 +11768,22 @@ update_one_slot(PyTypeObject *type, pytype_slotdef *p, pytype_slotdef **next_p,
             ((PyWrapperDescrObject *)descr)->d_base->name_strobj == p->name_strobj) {
             void **tptr;
             size_t index = (p - slotdefs);
-            if (slotdefs_name_counts[index] == 1) {
-                tptr = slotptr(type, p->offset);
+            if (slotdefs_dups[index][0] > 1) {
+                tptr = NULL;
+                for (size_t i = 1; i <= slotdefs_dups[index][0]; i++) {
+                    pytype_slotdef *q = &slotdefs[slotdefs_dups[index][i]];
+                    void **qptr = slotptr(type, q->offset);
+                    if (qptr == NULL || *qptr == NULL)
+                        continue;
+                    if (tptr != NULL) {
+                        tptr = NULL;
+                        break;
+                    }
+                    tptr = qptr;
+                }
             }
             else {
-                tptr = NULL;
+                tptr = slotptr(type, offset);
             }
 
             if (tptr == NULL || tptr == ptr)
@@ -12034,7 +12045,7 @@ _PyType_InitSlotDefs(PyInterpreterState *interp)
         Py_CLEAR(bytearray);
     }
 
-    memset(slotdefs_name_counts, 0, sizeof(slotdefs_name_counts));
+    memset(slotdefs_dups, -1, sizeof(slotdefs_dups));
 
     Py_ssize_t pos = 0;
     PyObject *key = NULL;
@@ -12044,7 +12055,7 @@ _PyType_InitSlotDefs(PyInterpreterState *interp)
         uint8_t n = data[0];
         for (uint8_t i = 0; i < n; i++) {
             uint8_t idx = data[i + 1];
-            slotdefs_name_counts[idx] = n;
+            memcpy(&slotdefs_dups[idx], data, sizeof(uint8_t) * (n + 1));
         }
     }
 
index cbec0bf262f0e01becde5601a10061bda1dd6255..d2489387f46caa0ceaa83eb512d9daa89bfc49c4 100644 (file)
@@ -351,7 +351,7 @@ Objects/obmalloc.c  -       obmalloc_state_initialized      -
 Objects/typeobject.c   -       name_op -
 Objects/typeobject.c   -       slotdefs        -
 # It initialized only once when main interpeter starts
-Objects/typeobject.c   -       slotdefs_name_counts    -
+Objects/typeobject.c   -       slotdefs_dups   -
 Objects/unicodeobject.c        -       stripfuncnames  -
 Objects/unicodeobject.c        -       utf7_category   -
 Objects/unicodeobject.c        unicode_decode_call_errorhandler_wchar  argparse        -