Skip to content

Commit c314e3e

Browse files
bpo-46503: Prevent an assert from firing when parsing some invalid \N sequences in f-strings. (GH-30865) (30867)
* bpo-46503: Prevent an assert from firing. Also fix one nearby tiny PEP-7 nit. * Added blurb. (cherry picked from commit 0daf721) Co-authored-by: Eric V. Smith <[email protected]> Co-authored-by: Eric V. Smith <[email protected]>
1 parent 3f1ea16 commit c314e3e

File tree

3 files changed

+19
-2
lines changed

3 files changed

+19
-2
lines changed

Lib/test/test_fstring.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -747,12 +747,16 @@ def test_misformed_unicode_character_name(self):
747747
# differently inside f-strings.
748748
self.assertAllRaise(SyntaxError, r"\(unicode error\) 'unicodeescape' codec can't decode bytes in position .*: malformed \\N character escape",
749749
[r"f'\N'",
750+
r"f'\N '",
751+
r"f'\N '", # See bpo-46503.
750752
r"f'\N{'",
751753
r"f'\N{GREEK CAPITAL LETTER DELTA'",
752754

753755
# Here are the non-f-string versions,
754756
# which should give the same errors.
755757
r"'\N'",
758+
r"'\N '",
759+
r"'\N '",
756760
r"'\N{'",
757761
r"'\N{GREEK CAPITAL LETTER DELTA'",
758762
])
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix an assert when parsing some invalid \N escape sequences in f-strings.

Parser/pegen/parse_string.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -444,12 +444,23 @@ fstring_find_literal(Parser *p, const char **str, const char *end, int raw,
444444
if (!raw && ch == '\\' && s < end) {
445445
ch = *s++;
446446
if (ch == 'N') {
447+
/* We need to look at and skip matching braces for "\N{name}"
448+
sequences because otherwise we'll think the opening '{'
449+
starts an expression, which is not the case with "\N".
450+
Keep looking for either a matched '{' '}' pair, or the end
451+
of the string. */
452+
447453
if (s < end && *s++ == '{') {
448454
while (s < end && *s++ != '}') {
449455
}
450456
continue;
451457
}
452-
break;
458+
459+
/* This is an invalid "\N" sequence, since it's a "\N" not
460+
followed by a "{". Just keep parsing this literal. This
461+
error will be caught later by
462+
decode_unicode_with_escapes(). */
463+
continue;
453464
}
454465
if (ch == '{' && warn_invalid_escape_sequence(p, ch, t) < 0) {
455466
return -1;
@@ -493,7 +504,8 @@ fstring_find_literal(Parser *p, const char **str, const char *end, int raw,
493504
*literal = PyUnicode_DecodeUTF8Stateful(literal_start,
494505
s - literal_start,
495506
NULL, NULL);
496-
} else {
507+
}
508+
else {
497509
*literal = decode_unicode_with_escapes(p, literal_start,
498510
s - literal_start, t);
499511
}

0 commit comments

Comments
 (0)