Skip to content

Commit 6c4e0bd

Browse files
authored
bpo-41060: Avoid SEGFAULT when calling GET_INVALID_TARGET in the grammar (GH-21020)
`GET_INVALID_TARGET` might unexpectedly return `NULL`, which if not caught will cause a SEGFAULT. Therefore, this commit introduces a new inline function `RAISE_SYNTAX_ERROR_INVALID_TARGET` that always checks for `GET_INVALID_TARGET` returning NULL and can be used in the grammar, replacing the long C ternary operation used till now.
1 parent 3ccb96c commit 6c4e0bd

File tree

4 files changed

+38
-26
lines changed

4 files changed

+38
-26
lines changed

Grammar/python.gram

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -653,9 +653,7 @@ invalid_assignment:
653653
| a=expression ':' expression ['=' annotated_rhs] {
654654
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "illegal target for annotation") }
655655
| (star_targets '=')* a=star_expressions '=' {
656-
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(
657-
GET_INVALID_TARGET(a),
658-
"cannot assign to %s", _PyPegen_get_expr_name(GET_INVALID_TARGET(a))) }
656+
RAISE_SYNTAX_ERROR_INVALID_TARGET(STAR_TARGETS, a) }
659657
| (star_targets '=')* a=yield_expr '=' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "assignment to yield expression not possible") }
660658
| a=star_expressions augassign (yield_expr | star_expressions) {
661659
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(
@@ -665,12 +663,7 @@ invalid_assignment:
665663
)}
666664
invalid_del_stmt:
667665
| 'del' a=star_expressions {
668-
GET_INVALID_DEL_TARGET(a) != NULL ?
669-
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(
670-
GET_INVALID_DEL_TARGET(a),
671-
"cannot delete %s", _PyPegen_get_expr_name(GET_INVALID_DEL_TARGET(a))
672-
) :
673-
RAISE_SYNTAX_ERROR("invalid syntax") }
666+
RAISE_SYNTAX_ERROR_INVALID_TARGET(DEL_TARGETS, a) }
674667
invalid_block:
675668
| NEWLINE !INDENT { RAISE_INDENTATION_ERROR("expected an indented block") }
676669
invalid_comprehension:
@@ -695,19 +688,11 @@ invalid_double_type_comments:
695688
RAISE_SYNTAX_ERROR("Cannot have two type comments on def") }
696689
invalid_with_item:
697690
| expression 'as' a=expression {
698-
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(
699-
GET_INVALID_TARGET(a),
700-
"cannot assign to %s", _PyPegen_get_expr_name(GET_INVALID_TARGET(a))
701-
) }
691+
RAISE_SYNTAX_ERROR_INVALID_TARGET(STAR_TARGETS, a) }
702692

703693
invalid_for_target:
704694
| ASYNC? 'for' a=star_expressions {
705-
GET_INVALID_FOR_TARGET(a) != NULL ?
706-
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(
707-
GET_INVALID_FOR_TARGET(a),
708-
"cannot assign to %s", _PyPegen_get_expr_name(GET_INVALID_FOR_TARGET(a))
709-
) :
710-
RAISE_SYNTAX_ERROR("invalid syntax") }
695+
RAISE_SYNTAX_ERROR_INVALID_TARGET(FOR_TARGETS, a) }
711696

712697
invalid_group:
713698
| '(' a=starred_expression ')' {

Lib/test/test_syntax.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,10 @@
199199
Traceback (most recent call last):
200200
SyntaxError: invalid syntax
201201
202+
>>> for a, b
203+
Traceback (most recent call last):
204+
SyntaxError: invalid syntax
205+
202206
>>> with a as b(): pass
203207
Traceback (most recent call last):
204208
SyntaxError: cannot assign to function call
@@ -223,6 +227,10 @@
223227
Traceback (most recent call last):
224228
SyntaxError: cannot assign to function call
225229
230+
>>> with a as b
231+
Traceback (most recent call last):
232+
SyntaxError: invalid syntax
233+
226234
>>> p = p =
227235
Traceback (most recent call last):
228236
SyntaxError: invalid syntax

Parser/parser.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14818,7 +14818,7 @@ invalid_assignment_rule(Parser *p)
1481814818
)
1481914819
{
1482014820
D(fprintf(stderr, "%*c+ invalid_assignment[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "((star_targets '='))* star_expressions '='"));
14821-
_res = RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( GET_INVALID_TARGET ( a ) , "cannot assign to %s" , _PyPegen_get_expr_name ( GET_INVALID_TARGET ( a ) ) );
14821+
_res = RAISE_SYNTAX_ERROR_INVALID_TARGET ( STAR_TARGETS , a );
1482214822
if (_res == NULL && PyErr_Occurred()) {
1482314823
p->error_indicator = 1;
1482414824
D(p->level--);
@@ -14922,7 +14922,7 @@ invalid_del_stmt_rule(Parser *p)
1492214922
)
1492314923
{
1492414924
D(fprintf(stderr, "%*c+ invalid_del_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'del' star_expressions"));
14925-
_res = GET_INVALID_DEL_TARGET ( a ) != NULL ? RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( GET_INVALID_DEL_TARGET ( a ) , "cannot delete %s" , _PyPegen_get_expr_name ( GET_INVALID_DEL_TARGET ( a ) ) ) : RAISE_SYNTAX_ERROR ( "invalid syntax" );
14925+
_res = RAISE_SYNTAX_ERROR_INVALID_TARGET ( DEL_TARGETS , a );
1492614926
if (_res == NULL && PyErr_Occurred()) {
1492714927
p->error_indicator = 1;
1492814928
D(p->level--);
@@ -15379,7 +15379,7 @@ invalid_with_item_rule(Parser *p)
1537915379
)
1538015380
{
1538115381
D(fprintf(stderr, "%*c+ invalid_with_item[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression 'as' expression"));
15382-
_res = RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( GET_INVALID_TARGET ( a ) , "cannot assign to %s" , _PyPegen_get_expr_name ( GET_INVALID_TARGET ( a ) ) );
15382+
_res = RAISE_SYNTAX_ERROR_INVALID_TARGET ( STAR_TARGETS , a );
1538315383
if (_res == NULL && PyErr_Occurred()) {
1538415384
p->error_indicator = 1;
1538515385
D(p->level--);
@@ -15427,7 +15427,7 @@ invalid_for_target_rule(Parser *p)
1542715427
)
1542815428
{
1542915429
D(fprintf(stderr, "%*c+ invalid_for_target[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "ASYNC? 'for' star_expressions"));
15430-
_res = GET_INVALID_FOR_TARGET ( a ) != NULL ? RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( GET_INVALID_FOR_TARGET ( a ) , "cannot assign to %s" , _PyPegen_get_expr_name ( GET_INVALID_FOR_TARGET ( a ) ) ) : RAISE_SYNTAX_ERROR ( "invalid syntax" );
15430+
_res = RAISE_SYNTAX_ERROR_INVALID_TARGET ( FOR_TARGETS , a );
1543115431
if (_res == NULL && PyErr_Occurred()) {
1543215432
p->error_indicator = 1;
1543315433
D(p->level--);

Parser/pegen.h

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -269,9 +269,28 @@ typedef enum {
269269
FOR_TARGETS
270270
} TARGETS_TYPE;
271271
expr_ty _PyPegen_get_invalid_target(expr_ty e, TARGETS_TYPE targets_type);
272-
#define GET_INVALID_TARGET(e) (expr_ty)CHECK(_PyPegen_get_invalid_target(e, STAR_TARGETS))
273-
#define GET_INVALID_DEL_TARGET(e) (expr_ty)CHECK_NULL_ALLOWED(_PyPegen_get_invalid_target(e, DEL_TARGETS))
274-
#define GET_INVALID_FOR_TARGET(e) (expr_ty)CHECK_NULL_ALLOWED(_PyPegen_get_invalid_target(e, FOR_TARGETS))
272+
#define RAISE_SYNTAX_ERROR_INVALID_TARGET(type, e) _RAISE_SYNTAX_ERROR_INVALID_TARGET(p, type, e)
273+
274+
Py_LOCAL_INLINE(void *)
275+
_RAISE_SYNTAX_ERROR_INVALID_TARGET(Parser *p, TARGETS_TYPE type, void *e)
276+
{
277+
expr_ty invalid_target = CHECK_NULL_ALLOWED(_PyPegen_get_invalid_target(e, type));
278+
if (invalid_target != NULL) {
279+
const char *msg;
280+
if (type == STAR_TARGETS || type == FOR_TARGETS) {
281+
msg = "cannot assign to %s";
282+
}
283+
else {
284+
msg = "cannot delete %s";
285+
}
286+
return RAISE_SYNTAX_ERROR_KNOWN_LOCATION(
287+
invalid_target,
288+
msg,
289+
_PyPegen_get_expr_name(invalid_target)
290+
);
291+
}
292+
return RAISE_SYNTAX_ERROR("invalid syntax");
293+
}
275294

276295
void *_PyPegen_arguments_parsing_error(Parser *, expr_ty);
277296
void *_PyPegen_nonparen_genexp_in_call(Parser *p, expr_ty args);

0 commit comments

Comments
 (0)