From 8a459c74283c417bd81bbbe7014c68e726076889 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Tue, 12 Sep 2023 15:46:00 -0700 Subject: [PATCH 1/2] gh-109341: Fix crash on compiling invalid AST including TypeAlias --- Lib/test/test_compile.py | 20 +++++++++++++++++++ ...-09-12-15-45-49.gh-issue-109341.4V5bkm.rst | 1 + Python/symtable.c | 7 ++++++- 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-09-12-15-45-49.gh-issue-109341.4V5bkm.rst diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index a8a519f573e663..5e72495cef96bd 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -478,6 +478,26 @@ def test_compile_ast(self): ast.body = [_ast.BoolOp()] self.assertRaises(TypeError, compile, ast, '', 'exec') + def test_compile_invalid_typealias(self): + # gh-109341 + m = ast.Module( + body=[ + ast.TypeAlias( + name=ast.Subscript( + value=ast.Name(id="foo", ctx=ast.Load()), + slice=ast.Constant(value="x"), + ctx=ast.Store(), + ), + type_params=[], + value=ast.Name(id="Callable", ctx=ast.Load()), + ) + ], + type_ignores=[], + ) + + with self.assertRaises(SyntaxError): + compile(ast.fix_missing_locations(m), "", "exec") + def test_dict_evaluation_order(self): i = 0 diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-12-15-45-49.gh-issue-109341.4V5bkm.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-12-15-45-49.gh-issue-109341.4V5bkm.rst new file mode 100644 index 00000000000000..9e99ef7eb73273 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-09-12-15-45-49.gh-issue-109341.4V5bkm.rst @@ -0,0 +1 @@ +Fix crash when compiling an invalid AST involving a :class:`ast.TypeAlias`. diff --git a/Python/symtable.c b/Python/symtable.c index d737c09203d31b..f474ac7fffb626 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -1581,7 +1581,12 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s) } case TypeAlias_kind: { VISIT(st, expr, s->v.TypeAlias.name); - assert(s->v.TypeAlias.name->kind == Name_kind); + // This is only possible for a manually created AST + if (s->v.TypeAlias.name->kind != Name_kind) { + PyErr_SetString(PyExc_SyntaxError, + "Type alias name must be a simple name"); + VISIT_QUIT(st, 0); + } PyObject *name = s->v.TypeAlias.name->v.Name.id; int is_in_class = st->st_cur->ste_type == ClassBlock; int is_generic = asdl_seq_LEN(s->v.TypeAlias.type_params) > 0; From f6c10f5a4ab44461e00e0ccd93b7cf062de3e008 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Tue, 12 Sep 2023 16:09:34 -0700 Subject: [PATCH 2/2] Do it in the AST validator instead --- Lib/test/test_compile.py | 2 +- Python/ast.c | 5 +++++ Python/symtable.c | 7 +------ 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index 5e72495cef96bd..1beccb4b56a301 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -495,7 +495,7 @@ def test_compile_invalid_typealias(self): type_ignores=[], ) - with self.assertRaises(SyntaxError): + with self.assertRaisesRegex(TypeError, "TypeAlias with non-Name name"): compile(ast.fix_missing_locations(m), "", "exec") def test_dict_evaluation_order(self): diff --git a/Python/ast.c b/Python/ast.c index 21cb38f8cbfb65..c3863d60576d37 100644 --- a/Python/ast.c +++ b/Python/ast.c @@ -768,6 +768,11 @@ validate_stmt(struct validator *state, stmt_ty stmt) validate_expr(state, stmt->v.AnnAssign.annotation, Load); break; case TypeAlias_kind: + if (stmt->v.TypeAlias.name->kind != Name_kind) { + PyErr_SetString(PyExc_TypeError, + "TypeAlias with non-Name name"); + return 0; + } ret = validate_expr(state, stmt->v.TypeAlias.name, Store) && validate_type_params(state, stmt->v.TypeAlias.type_params) && validate_expr(state, stmt->v.TypeAlias.value, Load); diff --git a/Python/symtable.c b/Python/symtable.c index f474ac7fffb626..d737c09203d31b 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -1581,12 +1581,7 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s) } case TypeAlias_kind: { VISIT(st, expr, s->v.TypeAlias.name); - // This is only possible for a manually created AST - if (s->v.TypeAlias.name->kind != Name_kind) { - PyErr_SetString(PyExc_SyntaxError, - "Type alias name must be a simple name"); - VISIT_QUIT(st, 0); - } + assert(s->v.TypeAlias.name->kind == Name_kind); PyObject *name = s->v.TypeAlias.name->v.Name.id; int is_in_class = st->st_cur->ste_type == ClassBlock; int is_generic = asdl_seq_LEN(s->v.TypeAlias.type_params) > 0;