diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py index 7d9d0c431a66ff..f7221955e3e042 100644 --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -1790,6 +1790,12 @@ def test_stdlib_validates(self): kwd_attrs=[], kwd_patterns=[ast.MatchStar()] ), + ast.MatchClass( + constant_true, # invalid name + patterns=[], + kwd_attrs=['True'], + kwd_patterns=[pattern_1] + ), ast.MatchSequence( [ ast.MatchStar("True") diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-14-18-56-54.gh-issue-104482.yaQsv8.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-14-18-56-54.gh-issue-104482.yaQsv8.rst new file mode 100644 index 00000000000000..07c09a3a84a62c --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-14-18-56-54.gh-issue-104482.yaQsv8.rst @@ -0,0 +1 @@ +Fix three error handling bugs in ast.c's validation of pattern matching statements. diff --git a/Python/ast.c b/Python/ast.c index a0321b58ba8cff..95179cb70281b2 100644 --- a/Python/ast.c +++ b/Python/ast.c @@ -46,6 +46,7 @@ static int validate_pattern(struct validator *, pattern_ty, int); static int validate_name(PyObject *name) { + assert(!PyErr_Occurred()); assert(PyUnicode_Check(name)); static const char * const forbidden[] = { "None", @@ -65,12 +66,12 @@ validate_name(PyObject *name) static int validate_comprehension(struct validator *state, asdl_comprehension_seq *gens) { - Py_ssize_t i; + assert(!PyErr_Occurred()); if (!asdl_seq_LEN(gens)) { PyErr_SetString(PyExc_ValueError, "comprehension with no generators"); return 0; } - for (i = 0; i < asdl_seq_LEN(gens); i++) { + for (Py_ssize_t i = 0; i < asdl_seq_LEN(gens); i++) { comprehension_ty comp = asdl_seq_GET(gens, i); if (!validate_expr(state, comp->target, Store) || !validate_expr(state, comp->iter, Load) || @@ -83,8 +84,8 @@ validate_comprehension(struct validator *state, asdl_comprehension_seq *gens) static int validate_keywords(struct validator *state, asdl_keyword_seq *keywords) { - Py_ssize_t i; - for (i = 0; i < asdl_seq_LEN(keywords); i++) + assert(!PyErr_Occurred()); + for (Py_ssize_t i = 0; i < asdl_seq_LEN(keywords); i++) if (!validate_expr(state, (asdl_seq_GET(keywords, i))->value, Load)) return 0; return 1; @@ -93,8 +94,8 @@ validate_keywords(struct validator *state, asdl_keyword_seq *keywords) static int validate_args(struct validator *state, asdl_arg_seq *args) { - Py_ssize_t i; - for (i = 0; i < asdl_seq_LEN(args); i++) { + assert(!PyErr_Occurred()); + for (Py_ssize_t i = 0; i < asdl_seq_LEN(args); i++) { arg_ty arg = asdl_seq_GET(args, i); VALIDATE_POSITIONS(arg); if (arg->annotation && !validate_expr(state, arg->annotation, Load)) @@ -121,6 +122,7 @@ expr_context_name(expr_context_ty ctx) static int validate_arguments(struct validator *state, arguments_ty args) { + assert(!PyErr_Occurred()); if (!validate_args(state, args->posonlyargs) || !validate_args(state, args->args)) { return 0; } @@ -149,6 +151,7 @@ validate_arguments(struct validator *state, arguments_ty args) static int validate_constant(struct validator *state, PyObject *value) { + assert(!PyErr_Occurred()); if (value == Py_None || value == Py_Ellipsis) return 1; @@ -205,6 +208,7 @@ validate_constant(struct validator *state, PyObject *value) static int validate_expr(struct validator *state, expr_ty exp, expr_context_ty ctx) { + assert(!PyErr_Occurred()); VALIDATE_POSITIONS(exp); int ret = -1; if (++state->recursion_depth > state->recursion_limit) { @@ -465,6 +469,7 @@ ensure_literal_complex(expr_ty exp) static int validate_pattern_match_value(struct validator *state, expr_ty exp) { + assert(!PyErr_Occurred()); if (!validate_expr(state, exp, Load)) { return 0; } @@ -518,6 +523,7 @@ validate_pattern_match_value(struct validator *state, expr_ty exp) static int validate_capture(PyObject *name) { + assert(!PyErr_Occurred()); if (_PyUnicode_EqualToASCIIString(name, "_")) { PyErr_Format(PyExc_ValueError, "can't capture name '_' in patterns"); return 0; @@ -528,6 +534,7 @@ validate_capture(PyObject *name) static int validate_pattern(struct validator *state, pattern_ty p, int star_ok) { + assert(!PyErr_Occurred()); VALIDATE_POSITIONS(p); int ret = -1; if (++state->recursion_depth > state->recursion_limit) { @@ -580,7 +587,9 @@ validate_pattern(struct validator *state, pattern_ty p, int star_ok) break; } } - + if (ret == 0) { + break; + } ret = validate_patterns(state, p->v.MatchMapping.patterns, /*star_ok=*/0); break; case MatchClass_kind: @@ -611,6 +620,9 @@ validate_pattern(struct validator *state, pattern_ty p, int star_ok) break; } } + if (ret == 0) { + break; + } for (Py_ssize_t i = 0; i < asdl_seq_LEN(p->v.MatchClass.kwd_attrs); i++) { PyObject *identifier = asdl_seq_GET(p->v.MatchClass.kwd_attrs, i); @@ -619,6 +631,9 @@ validate_pattern(struct validator *state, pattern_ty p, int star_ok) break; } } + if (ret == 0) { + break; + } if (!validate_patterns(state, p->v.MatchClass.patterns, /*star_ok=*/0)) { ret = 0; @@ -685,6 +700,7 @@ _validate_nonempty_seq(asdl_seq *seq, const char *what, const char *owner) static int validate_assignlist(struct validator *state, asdl_expr_seq *targets, expr_context_ty ctx) { + assert(!PyErr_Occurred()); return validate_nonempty_seq(targets, "targets", ctx == Del ? "Delete" : "Assign") && validate_exprs(state, targets, ctx, 0); } @@ -692,15 +708,16 @@ validate_assignlist(struct validator *state, asdl_expr_seq *targets, expr_contex static int validate_body(struct validator *state, asdl_stmt_seq *body, const char *owner) { + assert(!PyErr_Occurred()); return validate_nonempty_seq(body, "body", owner) && validate_stmts(state, body); } static int validate_stmt(struct validator *state, stmt_ty stmt) { + assert(!PyErr_Occurred()); VALIDATE_POSITIONS(stmt); int ret = -1; - Py_ssize_t i; if (++state->recursion_depth > state->recursion_limit) { PyErr_SetString(PyExc_RecursionError, "maximum recursion depth exceeded during compilation"); @@ -771,7 +788,7 @@ validate_stmt(struct validator *state, stmt_ty stmt) case With_kind: if (!validate_nonempty_seq(stmt->v.With.items, "items", "With")) return 0; - for (i = 0; i < asdl_seq_LEN(stmt->v.With.items); i++) { + for (Py_ssize_t i = 0; i < asdl_seq_LEN(stmt->v.With.items); i++) { withitem_ty item = asdl_seq_GET(stmt->v.With.items, i); if (!validate_expr(state, item->context_expr, Load) || (item->optional_vars && !validate_expr(state, item->optional_vars, Store))) @@ -782,7 +799,7 @@ validate_stmt(struct validator *state, stmt_ty stmt) case AsyncWith_kind: if (!validate_nonempty_seq(stmt->v.AsyncWith.items, "items", "AsyncWith")) return 0; - for (i = 0; i < asdl_seq_LEN(stmt->v.AsyncWith.items); i++) { + for (Py_ssize_t i = 0; i < asdl_seq_LEN(stmt->v.AsyncWith.items); i++) { withitem_ty item = asdl_seq_GET(stmt->v.AsyncWith.items, i); if (!validate_expr(state, item->context_expr, Load) || (item->optional_vars && !validate_expr(state, item->optional_vars, Store))) @@ -795,7 +812,7 @@ validate_stmt(struct validator *state, stmt_ty stmt) || !validate_nonempty_seq(stmt->v.Match.cases, "cases", "Match")) { return 0; } - for (i = 0; i < asdl_seq_LEN(stmt->v.Match.cases); i++) { + for (Py_ssize_t i = 0; i < asdl_seq_LEN(stmt->v.Match.cases); i++) { match_case_ty m = asdl_seq_GET(stmt->v.Match.cases, i); if (!validate_pattern(state, m->pattern, /*star_ok=*/0) || (m->guard && !validate_expr(state, m->guard, Load)) @@ -830,7 +847,7 @@ validate_stmt(struct validator *state, stmt_ty stmt) PyErr_SetString(PyExc_ValueError, "Try has orelse but no except handlers"); return 0; } - for (i = 0; i < asdl_seq_LEN(stmt->v.Try.handlers); i++) { + for (Py_ssize_t i = 0; i < asdl_seq_LEN(stmt->v.Try.handlers); i++) { excepthandler_ty handler = asdl_seq_GET(stmt->v.Try.handlers, i); VALIDATE_POSITIONS(handler); if ((handler->v.ExceptHandler.type && @@ -856,7 +873,7 @@ validate_stmt(struct validator *state, stmt_ty stmt) PyErr_SetString(PyExc_ValueError, "TryStar has orelse but no except handlers"); return 0; } - for (i = 0; i < asdl_seq_LEN(stmt->v.TryStar.handlers); i++) { + for (Py_ssize_t i = 0; i < asdl_seq_LEN(stmt->v.TryStar.handlers); i++) { excepthandler_ty handler = asdl_seq_GET(stmt->v.TryStar.handlers, i); if ((handler->v.ExceptHandler.type && !validate_expr(state, handler->v.ExceptHandler.type, Load)) || @@ -916,8 +933,8 @@ validate_stmt(struct validator *state, stmt_ty stmt) static int validate_stmts(struct validator *state, asdl_stmt_seq *seq) { - Py_ssize_t i; - for (i = 0; i < asdl_seq_LEN(seq); i++) { + assert(!PyErr_Occurred()); + for (Py_ssize_t i = 0; i < asdl_seq_LEN(seq); i++) { stmt_ty stmt = asdl_seq_GET(seq, i); if (stmt) { if (!validate_stmt(state, stmt)) @@ -935,8 +952,8 @@ validate_stmts(struct validator *state, asdl_stmt_seq *seq) static int validate_exprs(struct validator *state, asdl_expr_seq *exprs, expr_context_ty ctx, int null_ok) { - Py_ssize_t i; - for (i = 0; i < asdl_seq_LEN(exprs); i++) { + assert(!PyErr_Occurred()); + for (Py_ssize_t i = 0; i < asdl_seq_LEN(exprs); i++) { expr_ty expr = asdl_seq_GET(exprs, i); if (expr) { if (!validate_expr(state, expr, ctx)) @@ -955,8 +972,8 @@ validate_exprs(struct validator *state, asdl_expr_seq *exprs, expr_context_ty ct static int validate_patterns(struct validator *state, asdl_pattern_seq *patterns, int star_ok) { - Py_ssize_t i; - for (i = 0; i < asdl_seq_LEN(patterns); i++) { + assert(!PyErr_Occurred()); + for (Py_ssize_t i = 0; i < asdl_seq_LEN(patterns); i++) { pattern_ty pattern = asdl_seq_GET(patterns, i); if (!validate_pattern(state, pattern, star_ok)) { return 0; @@ -972,6 +989,7 @@ validate_patterns(struct validator *state, asdl_pattern_seq *patterns, int star_ int _PyAST_Validate(mod_ty mod) { + assert(!PyErr_Occurred()); int res = -1; struct validator state; PyThreadState *tstate;