From c611c39620a4ed83c5349c5c01013bbd2ba82725 Mon Sep 17 00:00:00 2001 From: Lysandros Nikolaou Date: Thu, 14 May 2020 03:15:55 +0300 Subject: [PATCH 1/3] bpo-40618: Disallow invalid targets in augassign and except clauses This PR fixes the new parser to disallow invalid targets in the following scenarios: - Augmented assignments must only accept a single target (Name, Attribute or Subscript), but no tuples or lists. - `except` clauses should only accept a single `Name` as target. --- Grammar/python.gram | 17 +++++---- Lib/test/test_peg_parser.py | 25 ++++++++++++++ Parser/pegen/parse.c | 69 ++++++++++++++++++------------------- 3 files changed, 66 insertions(+), 45 deletions(-) diff --git a/Grammar/python.gram b/Grammar/python.gram index 84c89330e3ee9d..9087c7aa718b17 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -89,12 +89,12 @@ assignment[stmt_ty]: "Variable annotation syntax is", _Py_AnnAssign(CHECK(_PyPegen_set_expr_context(p, a, Store)), b, c, 1, EXTRA) ) } - | a=('(' b=inside_paren_ann_assign_target ')' { b } - | ann_assign_subscript_attribute_target) ':' b=expression c=['=' d=annotated_rhs { d }] { + | a=('(' b=single_target ')' { b } + | single_subscript_attribute_target) ':' b=expression c=['=' d=annotated_rhs { d }] { CHECK_VERSION(6, "Variable annotations syntax is", _Py_AnnAssign(a, b, c, 0, EXTRA)) } | a=(z=star_targets '=' { z })+ b=(yield_expr | star_expressions) tc=[TYPE_COMMENT] { _Py_Assign(a, b, NEW_TYPE_COMMENT(p, tc), EXTRA) } - | a=target b=augassign c=(yield_expr | star_expressions) { + | a=single_target b=augassign c=(yield_expr | star_expressions) { _Py_AugAssign(a, b->kind, c, EXTRA) } | invalid_assignment @@ -185,7 +185,7 @@ try_stmt[stmt_ty]: | 'try' ':' b=block f=finally_block { _Py_Try(b, NULL, NULL, f, EXTRA) } | 'try' ':' b=block ex=except_block+ el=[else_block] f=[finally_block] { _Py_Try(b, ex, el, f, EXTRA) } except_block[excepthandler_ty]: - | 'except' e=expression t=['as' z=target { z }] ':' b=block { + | 'except' e=expression t=['as' z=NAME { z }] ':' b=block { _Py_ExceptHandler(e, (t) ? ((expr_ty) t)->v.Name.id : NULL, b, EXTRA) } | 'except' ':' b=block { _Py_ExceptHandler(NULL, NULL, b, EXTRA) } finally_block[asdl_seq*]: 'finally' ':' a=block { a } @@ -573,12 +573,11 @@ star_atom[expr_ty]: | '(' a=[star_targets_seq] ')' { _Py_Tuple(a, Store, EXTRA) } | '[' a=[star_targets_seq] ']' { _Py_List(a, Store, EXTRA) } -inside_paren_ann_assign_target[expr_ty]: - | ann_assign_subscript_attribute_target +single_target[expr_ty]: + | single_subscript_attribute_target | a=NAME { _PyPegen_set_expr_context(p, a, Store) } - | '(' a=inside_paren_ann_assign_target ')' { a } - -ann_assign_subscript_attribute_target[expr_ty]: + | '(' a=single_target ')' { a } +single_subscript_attribute_target[expr_ty]: | a=t_primary '.' b=NAME !t_lookahead { _Py_Attribute(a, b->v.Name.id, Store, EXTRA) } | a=t_primary '[' b=slices ']' !t_lookahead { _Py_Subscript(a, b, Store, EXTRA) } diff --git a/Lib/test/test_peg_parser.py b/Lib/test/test_peg_parser.py index df2d46d8827f0e..71e071940de2f4 100644 --- a/Lib/test/test_peg_parser.py +++ b/Lib/test/test_peg_parser.py @@ -35,6 +35,9 @@ ('attribute_simple', 'a.b'), ('attributes_subscript', 'a.b[0]'), ('augmented_assignment', 'x += 42'), + ('augmented_assignment_attribute', 'a.b.c += 42'), + ('augmented_assignment_paren', '(x) += 42'), + ('augmented_assignment_paren_subscript', '(x[0]) -= 42'), ('binop_add', '1 + 1'), ('binop_add_multiple', '1 + 1 + 1 + 1'), ('binop_all', '1 + 2 * 5 + 3 ** 2 - -3'), @@ -547,6 +550,11 @@ def f(*a, b): with a as (x, y): pass '''), + ('with_list_target', + ''' + with a as [x, y]: + pass + '''), ('yield', 'yield'), ('yield_expr', 'yield a'), ('yield_from', 'yield from a'), @@ -560,6 +568,9 @@ def f(*a, b): ("annotation_tuple", "(a,): int"), ("annotation_tuple_without_paren", "a,: int"), ("assignment_keyword", "a = if"), + ("augmented_assignment_list", "[a, b] += 1"), + ("augmented_assignment_tuple", "a, b += 1"), + ("augmented_assignment_tuple_paren", "(a, b) += (1, 2)"), ("comprehension_lambda", "(a for a in lambda: b)"), ("comprehension_else", "(a for a in b if c else d"), ("del_call", "del a()"), @@ -589,6 +600,20 @@ def f(): a """), ("not_terminated_string", "a = 'example"), + ("try_except_attribute_target", + """ + try: + pass + except Exception as a.b: + pass + """), + ("try_except_subscript_target", + """ + try: + pass + except Exception as a[0]: + pass + """), ] FAIL_SPECIALIZED_MESSAGE_CASES = [ diff --git a/Parser/pegen/parse.c b/Parser/pegen/parse.c index b1b248187ea3ed..851d17226d162f 100644 --- a/Parser/pegen/parse.c +++ b/Parser/pegen/parse.c @@ -199,8 +199,8 @@ static KeywordToken *reserved_keywords[] = { #define star_targets_seq_type 1128 #define star_target_type 1129 #define star_atom_type 1130 -#define inside_paren_ann_assign_target_type 1131 -#define ann_assign_subscript_attribute_target_type 1132 +#define single_target_type 1131 +#define single_subscript_attribute_target_type 1132 #define del_targets_type 1133 #define del_target_type 1134 #define del_t_atom_type 1135 @@ -501,8 +501,8 @@ static expr_ty star_targets_rule(Parser *p); static asdl_seq* star_targets_seq_rule(Parser *p); static expr_ty star_target_rule(Parser *p); static expr_ty star_atom_rule(Parser *p); -static expr_ty inside_paren_ann_assign_target_rule(Parser *p); -static expr_ty ann_assign_subscript_attribute_target_rule(Parser *p); +static expr_ty single_target_rule(Parser *p); +static expr_ty single_subscript_attribute_target_rule(Parser *p); static asdl_seq* del_targets_rule(Parser *p); static expr_ty del_target_rule(Parser *p); static expr_ty del_t_atom_rule(Parser *p); @@ -1590,9 +1590,9 @@ compound_stmt_rule(Parser *p) // assignment: // | NAME ':' expression ['=' annotated_rhs] -// | ('(' inside_paren_ann_assign_target ')' | ann_assign_subscript_attribute_target) ':' expression ['=' annotated_rhs] +// | ('(' single_target ')' | single_subscript_attribute_target) ':' expression ['=' annotated_rhs] // | ((star_targets '='))+ (yield_expr | star_expressions) TYPE_COMMENT? -// | target augassign (yield_expr | star_expressions) +// | single_target augassign (yield_expr | star_expressions) // | invalid_assignment static stmt_ty assignment_rule(Parser *p) @@ -1642,13 +1642,13 @@ assignment_rule(Parser *p) } p->mark = _mark; } - { // ('(' inside_paren_ann_assign_target ')' | ann_assign_subscript_attribute_target) ':' expression ['=' annotated_rhs] + { // ('(' single_target ')' | single_subscript_attribute_target) ':' expression ['=' annotated_rhs] Token * _literal; void *a; expr_ty b; void *c; if ( - (a = _tmp_20_rule(p)) // '(' inside_paren_ann_assign_target ')' | ann_assign_subscript_attribute_target + (a = _tmp_20_rule(p)) // '(' single_target ')' | single_subscript_attribute_target && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -1703,12 +1703,12 @@ assignment_rule(Parser *p) } p->mark = _mark; } - { // target augassign (yield_expr | star_expressions) + { // single_target augassign (yield_expr | star_expressions) expr_ty a; AugOperator* b; void *c; if ( - (a = target_rule(p)) // target + (a = single_target_rule(p)) // single_target && (b = augassign_rule(p)) // augassign && @@ -3350,7 +3350,7 @@ try_stmt_rule(Parser *p) return _res; } -// except_block: 'except' expression ['as' target] ':' block | 'except' ':' block +// except_block: 'except' expression ['as' NAME] ':' block | 'except' ':' block static excepthandler_ty except_block_rule(Parser *p) { @@ -3367,7 +3367,7 @@ except_block_rule(Parser *p) UNUSED(_start_lineno); // Only used by EXTRA macro int _start_col_offset = p->tokens[_mark]->col_offset; UNUSED(_start_col_offset); // Only used by EXTRA macro - { // 'except' expression ['as' target] ':' block + { // 'except' expression ['as' NAME] ':' block Token * _keyword; Token * _literal; asdl_seq* b; @@ -3378,7 +3378,7 @@ except_block_rule(Parser *p) && (e = expression_rule(p)) // expression && - (t = _tmp_48_rule(p), 1) // ['as' target] + (t = _tmp_48_rule(p), 1) // ['as' NAME] && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -9605,25 +9605,22 @@ star_atom_rule(Parser *p) return _res; } -// inside_paren_ann_assign_target: -// | ann_assign_subscript_attribute_target -// | NAME -// | '(' inside_paren_ann_assign_target ')' +// single_target: single_subscript_attribute_target | NAME | '(' single_target ')' static expr_ty -inside_paren_ann_assign_target_rule(Parser *p) +single_target_rule(Parser *p) { if (p->error_indicator) { return NULL; } expr_ty _res = NULL; int _mark = p->mark; - { // ann_assign_subscript_attribute_target - expr_ty ann_assign_subscript_attribute_target_var; + { // single_subscript_attribute_target + expr_ty single_subscript_attribute_target_var; if ( - (ann_assign_subscript_attribute_target_var = ann_assign_subscript_attribute_target_rule(p)) // ann_assign_subscript_attribute_target + (single_subscript_attribute_target_var = single_subscript_attribute_target_rule(p)) // single_subscript_attribute_target ) { - _res = ann_assign_subscript_attribute_target_var; + _res = single_subscript_attribute_target_var; goto done; } p->mark = _mark; @@ -9643,14 +9640,14 @@ inside_paren_ann_assign_target_rule(Parser *p) } p->mark = _mark; } - { // '(' inside_paren_ann_assign_target ')' + { // '(' single_target ')' Token * _literal; Token * _literal_1; expr_ty a; if ( (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (a = inside_paren_ann_assign_target_rule(p)) // inside_paren_ann_assign_target + (a = single_target_rule(p)) // single_target && (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) @@ -9669,11 +9666,11 @@ inside_paren_ann_assign_target_rule(Parser *p) return _res; } -// ann_assign_subscript_attribute_target: +// single_subscript_attribute_target: // | t_primary '.' NAME !t_lookahead // | t_primary '[' slices ']' !t_lookahead static expr_ty -ann_assign_subscript_attribute_target_rule(Parser *p) +single_subscript_attribute_target_rule(Parser *p) { if (p->error_indicator) { return NULL; @@ -11907,7 +11904,7 @@ _tmp_19_rule(Parser *p) return _res; } -// _tmp_20: '(' inside_paren_ann_assign_target ')' | ann_assign_subscript_attribute_target +// _tmp_20: '(' single_target ')' | single_subscript_attribute_target static void * _tmp_20_rule(Parser *p) { @@ -11916,14 +11913,14 @@ _tmp_20_rule(Parser *p) } void * _res = NULL; int _mark = p->mark; - { // '(' inside_paren_ann_assign_target ')' + { // '(' single_target ')' Token * _literal; Token * _literal_1; expr_ty b; if ( (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (b = inside_paren_ann_assign_target_rule(p)) // inside_paren_ann_assign_target + (b = single_target_rule(p)) // single_target && (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) @@ -11937,13 +11934,13 @@ _tmp_20_rule(Parser *p) } p->mark = _mark; } - { // ann_assign_subscript_attribute_target - expr_ty ann_assign_subscript_attribute_target_var; + { // single_subscript_attribute_target + expr_ty single_subscript_attribute_target_var; if ( - (ann_assign_subscript_attribute_target_var = ann_assign_subscript_attribute_target_rule(p)) // ann_assign_subscript_attribute_target + (single_subscript_attribute_target_var = single_subscript_attribute_target_rule(p)) // single_subscript_attribute_target ) { - _res = ann_assign_subscript_attribute_target_var; + _res = single_subscript_attribute_target_var; goto done; } p->mark = _mark; @@ -13073,7 +13070,7 @@ _loop1_47_rule(Parser *p) return _seq; } -// _tmp_48: 'as' target +// _tmp_48: 'as' NAME static void * _tmp_48_rule(Parser *p) { @@ -13082,13 +13079,13 @@ _tmp_48_rule(Parser *p) } void * _res = NULL; int _mark = p->mark; - { // 'as' target + { // 'as' NAME Token * _keyword; expr_ty z; if ( (_keyword = _PyPegen_expect_token(p, 531)) // token='as' && - (z = target_rule(p)) // target + (z = _PyPegen_name_token(p)) // NAME ) { _res = z; From 1bb434aea779e8b0fbf6666e3572ce2547fc93df Mon Sep 17 00:00:00 2001 From: Lysandros Nikolaou Date: Thu, 14 May 2020 03:37:26 +0300 Subject: [PATCH 2/3] Add more tests --- Lib/test/test_grammar.py | 5 ++++- Lib/test/test_syntax.py | 10 ++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_grammar.py b/Lib/test/test_grammar.py index 02ba8a8b1579a5..e1a402e2b463b1 100644 --- a/Lib/test/test_grammar.py +++ b/Lib/test/test_grammar.py @@ -1279,7 +1279,7 @@ def __getitem__(self, i): def test_try(self): ### try_stmt: 'try' ':' suite (except_clause ':' suite)+ ['else' ':' suite] ### | 'try' ':' suite 'finally' ':' suite - ### except_clause: 'except' [expr ['as' expr]] + ### except_clause: 'except' [expr ['as' NAME]] try: 1/0 except ZeroDivisionError: @@ -1297,6 +1297,9 @@ def test_try(self): except (EOFError, TypeError, ZeroDivisionError) as msg: pass try: pass finally: pass + with self.assertRaises(SyntaxError): + compile("try:\n pass\nexcept Exception as a.b:\n pass", "?", "exec") + compile("try:\n pass\nexcept Exception as a[b]:\n pass", "?", "exec") def test_suite(self): # simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py index 06636ae8a149a4..d729f45578ed60 100644 --- a/Lib/test/test_syntax.py +++ b/Lib/test/test_syntax.py @@ -129,6 +129,16 @@ Traceback (most recent call last): SyntaxError: cannot assign to conditional expression +>>> a, b += 1, 2 +Traceback (most recent call last): +SyntaxError: invalid syntax +>>> (a, b) += 1, 2 +Traceback (most recent call last): +SyntaxError: cannot assign to tuple +>>> [a, b] += 1, 2 +Traceback (most recent call last): +SyntaxError: cannot assign to list + From compiler_complex_args(): >>> def f(None=1): From 8301bb23323e96064fff99b334316708e10d9d68 Mon Sep 17 00:00:00 2001 From: Lysandros Nikolaou Date: Thu, 14 May 2020 03:42:51 +0300 Subject: [PATCH 3/3] Update Lib/test/test_syntax.py Co-authored-by: Pablo Galindo --- Lib/test/test_syntax.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py index d729f45578ed60..a3a101534628a2 100644 --- a/Lib/test/test_syntax.py +++ b/Lib/test/test_syntax.py @@ -132,9 +132,11 @@ >>> a, b += 1, 2 Traceback (most recent call last): SyntaxError: invalid syntax + >>> (a, b) += 1, 2 Traceback (most recent call last): SyntaxError: cannot assign to tuple + >>> [a, b] += 1, 2 Traceback (most recent call last): SyntaxError: cannot assign to list pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy