From 7d1d3e9d1d9ec1169422ea29dd751bffae535373 Mon Sep 17 00:00:00 2001 From: Alex Curtiss Date: Mon, 26 Sep 2022 01:12:58 -0600 Subject: [PATCH 1/5] String parser no longer crashes on null characters --- Lib/test/test_null.py | Bin 0 -> 36 bytes Parser/string_parser.c | 12 ++++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 Lib/test/test_null.py diff --git a/Lib/test/test_null.py b/Lib/test/test_null.py new file mode 100644 index 0000000000000000000000000000000000000000..7a9e8da6dcd6b34e89332e42acac681615b33844 GIT binary patch literal 36 lcmY#Z(ACmaNX}2m%uBaY$Vn{8%+oaliE$|@DRD7?NdTxk2gCpX literal 0 HcmV?d00001 diff --git a/Parser/string_parser.c b/Parser/string_parser.c index 5df7ae8bec04b25..2549646a004873b 100644 --- a/Parser/string_parser.c +++ b/Parser/string_parser.c @@ -249,12 +249,13 @@ _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; } - size_t len; int quote = Py_CHARMASK(*s); int bytesmode = 0; int rawmode = 0; @@ -263,13 +264,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,7 +289,7 @@ _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); From 15dfa859074eae1d8ec4db00126daee8bd6c1bcc Mon Sep 17 00:00:00 2001 From: Alex Curtiss Date: Mon, 26 Sep 2022 10:39:44 -0600 Subject: [PATCH 2/5] Removed test, which is blocked by issue #96670 --- Lib/test/test_null.py | Bin 36 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Lib/test/test_null.py diff --git a/Lib/test/test_null.py b/Lib/test/test_null.py deleted file mode 100644 index 7a9e8da6dcd6b34e89332e42acac681615b33844..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36 lcmY#Z(ACmaNX}2m%uBaY$Vn{8%+oaliE$|@DRD7?NdTxk2gCpX From 883f6f57dc7e83c4a4240814f296e7100679e485 Mon Sep 17 00:00:00 2001 From: Alex Curtiss Date: Mon, 26 Sep 2022 16:47:26 -0600 Subject: [PATCH 3/5] Moved the INT_MAX length check to the top of the string parser. --- Parser/string_parser.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Parser/string_parser.c b/Parser/string_parser.c index 2549646a004873b..81d5001f3651daa 100644 --- a/Parser/string_parser.c +++ b/Parser/string_parser.c @@ -256,6 +256,11 @@ _PyPegen_parse_string(Parser *p, Token *t) return NULL; } + if (len > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, "string to parse is too long"); + return NULL; + } + int quote = Py_CHARMASK(*s); int bytesmode = 0; int rawmode = 0; @@ -294,10 +299,6 @@ _PyPegen_parse_string(Parser *p, Token *t) // 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(); From d62c4e29b88fd4e8c172a213db6b3cf2d254c2a0 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Mon, 26 Sep 2022 16:46:55 +0000 Subject: [PATCH 4/5] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2022-09-26-16-46-54.gh-issue-96670.-n9hqb.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-09-26-16-46-54.gh-issue-96670.-n9hqb.rst 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 000000000000000..20371fb3458ecc1 --- /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. From 7f371698cab64c521e4c3c1ccdb7a41e31cf90a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Wed, 21 Oct 2026 03:29:49 +0200 Subject: [PATCH 5/5] Fix CI: move news entry out of spaced directory (gh-96670) The blurb-no-space-core-and-builtins lint hook rejects news files under 'Core and Builtins/'; move it to 'Core_and_Builtins/'. Co-authored-by: Muse Code (Meta Muse Spark) --- .../2022-09-26-16-46-54.gh-issue-96670.-n9hqb.rst | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Misc/NEWS.d/next/{Core and Builtins => Core_and_Builtins}/2022-09-26-16-46-54.gh-issue-96670.-n9hqb.rst (100%) 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 similarity index 100% rename from Misc/NEWS.d/next/Core and Builtins/2022-09-26-16-46-54.gh-issue-96670.-n9hqb.rst rename to Misc/NEWS.d/next/Core_and_Builtins/2022-09-26-16-46-54.gh-issue-96670.-n9hqb.rst