8000 bpo-46503: Prevent an assert from firing when parsing some invalid \N… · python/cpython@894e8c1 · GitHub
[go: up one dir, main page]

Skip to content

Commit 894e8c1

Browse files
bpo-46503: Prevent an assert from firing when parsing some invalid \N sequences in f-strings. (GH-30865) (GH-30866)
* 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 <ericvsmith@users.noreply.github.com> Co-authored-by: Eric V. Smith <ericvsmith@users.noreply.github.com>
1 parent eaeb994 commit 894e8c1

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
@@ -746,12 +746,16 @@ def test_misformed_unicode_character_name(self):
746746
# differently inside f-strings.
747747
self.assertAllRaise(SyntaxError, r"\(unicode error\) 'unicodeescape' codec can't decode bytes in position .*: malformed \\N character escape",
748748
[r"f'\N'",
749+
r"f'\N '",
750+
r"f'\N '", # See bpo-46503.
749751
r"f'\N{'",
750752
r"f'\N{GREEK CAPITAL LETTER DELTA'",
751753

752754
# Here are the non-f-string versions,
753755
# which should give the same errors.
754756
r"'\N'",
757+
r"'\N '",
758+
r"'\N '",
755759
r"'\N{'",
756760
r"'\N{GREEK CAPITAL LETTER DELTA'",
757761
])
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/string_parser.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -442,12 +442,23 @@ fstring_find_literal(Parser *p, const char **str, const char *end, int raw,
442442
if (!raw && ch == '\\' && s < end) {
443443
ch = *s++;
444444
if (ch == 'N') {
445+
/* We need to look at and skip matching braces for "\N{name}"
446+
sequences because otherwise we'll think the opening '{'
447+
starts an expression, which is not the case with "\N".
448+
Keep looking for either a matched '{' '}' pair, or the end
449+
of the string. */
450+
445451
if (s < end && *s++ == '{') {
446452
while (s < end && *s++ != '}') {
447453
}
448454
continue;
449455
}
450-
break;
456+
457+
/* This is an invalid "\N" sequence, since it's a "\N" not
458+
followed by a "{". Just keep parsing this literal. This
459+
error will be caught later by
460+
decode_unicode_with_escapes(). */
461+
continue;
451462
}
452463
if (ch == '{' && warn_invalid_escape_sequence(p, ch, t) < 0) {
453464
return -1;
@@ -491,7 +502,8 @@ fstring_find_literal(Parser *p, const char **str, const char *end, int raw,
491502
*literal = PyUnicode_DecodeUTF8Stateful(literal_start,
492503
s - literal_start,
493504
NULL, NULL);
494-
} else {
505+
}
506+
else {
495507
*literal = decode_unicode_with_escapes(p, literal_start,
496508
s - literal_start, t);
497509
}

0 commit comments

Comments
 (0)
0