https://github.com/python/cpython/commit/3d3e7b0adaf62a2ed9925f93c3fad9cadd835b4a
commit: 3d3e7b0adaf62a2ed9925f93c3fad9cadd835b4a
branch: 3.12
author: Tomasz Pytel <tompy...@gmail.com>
committer: JelleZijlstra <jelle.zijls...@gmail.com>
date: 2025-04-04T15:48:57Z
summary:

[3.12] gh-128632: fix segfault on nested __classdict__ type param (GH… (#132090)

(cherry picked from commit 891c61c1fa480928dd60cce8bbc8764630c95025)

Co-authored-by: Tomasz Pytel <tompy...@gmail.com>

files:
A 
Misc/NEWS.d/next/Core_and_Builtins/2025-01-11-20-11-28.gh-issue-128632.ryhnKs.rst
M Lib/test/test_syntax.py
M Python/symtable.c

diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py
index 099667c7356151..36a7f5a873dc8f 100644
--- a/Lib/test/test_syntax.py
+++ b/Lib/test/test_syntax.py
@@ -2244,6 +2244,25 @@ def test_continuation_bad_indentation(self):
 
         self.assertRaises(IndentationError, exec, code)
 
+    @support.cpython_only
+    def test_disallowed_type_param_names(self):
+        # See gh-128632
+
+        self._check_error(f"class A[__classdict__]: pass",
+                        f"reserved name '__classdict__' cannot be used for 
type parameter")
+        self._check_error(f"def f[__classdict__](): pass",
+                        f"reserved name '__classdict__' cannot be used for 
type parameter")
+        self._check_error(f"type T[__classdict__] = tuple[__classdict__]",
+                        f"reserved name '__classdict__' cannot be used for 
type parameter")
+
+        # These compilations are here to make sure __class__, __classcell__ 
and __classdictcell__
+        # don't break in the future like __classdict__ did in this case.
+        for name in ('__class__', '__classcell__', '__classdictcell__'):
+            compile(f"""
+class A:
+    class B[{name}]: pass
+                """, "<testcase>", mode="exec")
+
     @support.cpython_only
     def test_nested_named_except_blocks(self):
         code = ""
diff --git 
a/Misc/NEWS.d/next/Core_and_Builtins/2025-01-11-20-11-28.gh-issue-128632.ryhnKs.rst
 
b/Misc/NEWS.d/next/Core_and_Builtins/2025-01-11-20-11-28.gh-issue-128632.ryhnKs.rst
new file mode 100644
index 00000000000000..8cb23fc2d9e78e
--- /dev/null
+++ 
b/Misc/NEWS.d/next/Core_and_Builtins/2025-01-11-20-11-28.gh-issue-128632.ryhnKs.rst
@@ -0,0 +1,2 @@
+Disallow ``__classdict__`` as the name of a type parameter. Using this
+name would previously crash the interpreter in some circumstances.
diff --git a/Python/symtable.c b/Python/symtable.c
index f99ca4fdd06fa2..da17485acdd411 100644
--- a/Python/symtable.c
+++ b/Python/symtable.c
@@ -2191,6 +2191,24 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
     VISIT_QUIT(st, 1);
 }
 
+static int
+symtable_visit_type_param_check_reserved_name(struct symtable *st, 
type_param_ty tp, identifier name)
+{
+    if (_PyUnicode_Equal(name, &_Py_ID(__classdict__))) {
+        PyObject *error_msg = PyUnicode_FromFormat("reserved name '%U' cannot 
be "
+                                                   "used for type parameter", 
name);
+        PyErr_SetObject(PyExc_SyntaxError, error_msg);
+        Py_DECREF(error_msg);
+        PyErr_RangedSyntaxLocationObject(st->st_filename,
+                                         tp->lineno,
+                                         tp->col_offset + 1,
+                                         tp->end_lineno,
+                                         tp->end_col_offset + 1);
+        return 0;
+    }
+    return 1;
+}
+
 static int
 symtable_visit_type_param(struct symtable *st, type_param_ty tp)
 {
@@ -2201,6 +2219,8 @@ symtable_visit_type_param(struct symtable *st, 
type_param_ty tp)
     }
     switch(tp->kind) {
     case TypeVar_kind:
+        if (!symtable_visit_type_param_check_reserved_name(st, tp, 
tp->v.TypeVar.name))
+            VISIT_QUIT(st, 0);
         if (!symtable_add_def(st, tp->v.TypeVar.name, DEF_TYPE_PARAM | 
DEF_LOCAL, LOCATION(tp)))
             VISIT_QUIT(st, 0);
         if (tp->v.TypeVar.bound) {
@@ -2219,10 +2239,14 @@ symtable_visit_type_param(struct symtable *st, 
type_param_ty tp)
         }
         break;
     case TypeVarTuple_kind:
+        if (!symtable_visit_type_param_check_reserved_name(st, tp, 
tp->v.TypeVarTuple.name))
+            VISIT_QUIT(st, 0);
         if (!symtable_add_def(st, tp->v.TypeVarTuple.name, DEF_TYPE_PARAM | 
DEF_LOCAL, LOCATION(tp)))
             VISIT_QUIT(st, 0);
         break;
     case ParamSpec_kind:
+        if (!symtable_visit_type_param_check_reserved_name(st, tp, 
tp->v.ParamSpec.name))
+            VISIT_QUIT(st, 0);
         if (!symtable_add_def(st, tp->v.ParamSpec.name, DEF_TYPE_PARAM | 
DEF_LOCAL, LOCATION(tp)))
             VISIT_QUIT(st, 0);
         break;

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to