diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2022-09-26-16-46-54.gh-issue-96670.-n9hqb.rst b/Misc/NEWS.d/next/Core_and_Builtins/2022-09-26-16-46-54.gh-issue-96670.-n9hqb.rst new file mode 100644 index 00000000000000..20371fb3458ecc --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2022-09-26-16-46-54.gh-issue-96670.-n9hqb.rst @@ -0,0 +1 @@ +Fix interpreter crash when a string literal contains a null character. diff --git a/Parser/string_parser.c b/Parser/string_parser.c index 5df7ae8bec04b2..81d5001f3651da 100644 --- a/Parser/string_parser.c +++ b/Parser/string_parser.c @@ -249,12 +249,18 @@ _PyPegen_decode_string(Parser *p, int raw, const char *s, size_t len, Token *t) PyObject * _PyPegen_parse_string(Parser *p, Token *t) { - const char *s = PyBytes_AsString(t->bytes); - if (s == NULL) { + char *s; + Py_ssize_t len; + + if (PyBytes_AsStringAndSize(t->bytes, &s, &len)) { + return NULL; + } + + if (len > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, "string to parse is too long"); return NULL; } - size_t len; int quote = Py_CHARMASK(*s); int bytesmode = 0; int rawmode = 0; @@ -263,13 +269,16 @@ _PyPegen_parse_string(Parser *p, Token *t) while (!bytesmode || !rawmode) { if (quote == 'b' || quote == 'B') { quote =(unsigned char)*++s; + len--; bytesmode = 1; } else if (quote == 'u' || quote == 'U') { quote = (unsigned char)*++s; + len--; } else if (quote == 'r' || quote == 'R') { quote = (unsigned char)*++s; + len--; rawmode = 1; } else { @@ -285,15 +294,11 @@ _PyPegen_parse_string(Parser *p, Token *t) /* Skip the leading quote char. */ s++; - len = strlen(s); + len--; // gh-120155: 's' contains at least the trailing quote, // so the code '--len' below is safe. assert(len >= 1); - if (len > INT_MAX) { - PyErr_SetString(PyExc_OverflowError, "string to parse is too long"); - return NULL; - } if (s[--len] != quote) { /* Last quote char must match the first. */ PyErr_BadInternalCall();