From b5b0da78e56e474051438717fdddcc144c011a63 Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Mon, 9 Dec 2024 13:33:12 +0530 Subject: [PATCH 01/23] gh-127740: For odd-length input to bytes.fromhex(...) change the error message to ValueError: fromhex() arg must be of even length --- Lib/test/test_bytes.py | 5 +++++ Objects/bytesobject.c | 15 ++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py index 9e1985bb3a7639..576499517b11c7 100644 --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -459,6 +459,11 @@ def test_fromhex(self): self.assertRaises(ValueError, self.type2test.fromhex, '\x00') self.assertRaises(ValueError, self.type2test.fromhex, '12 \x00 34') + # For odd number of character(s) + with self.assertRaises(ValueError) as cm: + self.type2test.fromhex("a") + self.assertIn("fromhex() arg must be of even length", str(cm.exception)) + for data, pos in ( # invalid first hexadecimal character ('12 x4 56', 3), diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 8c7651f0f3aa45..b076d922e2da71 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -2490,7 +2490,7 @@ PyObject* _PyBytes_FromHex(PyObject *string, int use_bytearray) { char *buf; - Py_ssize_t hexlen, invalid_char; + Py_ssize_t hexlen, invalid_char,real_len=0; unsigned int top, bot; const Py_UCS1 *str, *end; _PyBytesWriter writer; @@ -2516,6 +2516,19 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray) } assert(PyUnicode_KIND(string) == PyUnicode_1BYTE_KIND); + + const Py_UCS1 *s = PyUnicode_1BYTE_DATA(string); + for (Py_ssize_t i = 0; i < hexlen; i++) { + if (!Py_ISSPACE(s[i])) { + real_len++; + } + } + if (real_len % 2 != 0) { + PyErr_SetString(PyExc_ValueError, + "fromhex() arg must be of even length"); + _PyBytesWriter_Dealloc(&writer); + return NULL; + } str = PyUnicode_1BYTE_DATA(string); /* This overestimates if there are spaces */ From 14b7d5eeff28bcadc0d9279aef53ed59eaed925d Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Mon, 9 Dec 2024 13:36:01 +0530 Subject: [PATCH 02/23] Introduce space between variables --- Objects/bytesobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index b076d922e2da71..01b895a245e268 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -2490,7 +2490,7 @@ PyObject* _PyBytes_FromHex(PyObject *string, int use_bytearray) { char *buf; - Py_ssize_t hexlen, invalid_char,real_len=0; + Py_ssize_t hexlen, invalid_char, real_len=0; unsigned int top, bot; const Py_UCS1 *str, *end; _PyBytesWriter writer; From f3bfe8537c59f6284d92b186f28c9c1304cfcc5f Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Mon, 9 Dec 2024 14:13:34 +0530 Subject: [PATCH 03/23] gh-127740: Improve code, consolidate two variables into one --- Objects/bytesobject.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 01b895a245e268..9dac36933d4e81 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -2516,10 +2516,9 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray) } assert(PyUnicode_KIND(string) == PyUnicode_1BYTE_KIND); - - const Py_UCS1 *s = PyUnicode_1BYTE_DATA(string); + str = PyUnicode_1BYTE_DATA(string); for (Py_ssize_t i = 0; i < hexlen; i++) { - if (!Py_ISSPACE(s[i])) { + if (!Py_ISSPACE(str[i])) { real_len++; } } @@ -2529,7 +2528,6 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray) _PyBytesWriter_Dealloc(&writer); return NULL; } - str = PyUnicode_1BYTE_DATA(string); /* This overestimates if there are spaces */ buf = _PyBytesWriter_Alloc(&writer, hexlen / 2); From 5a55e24dbe9d63f1b23a2cfe910add02f42802cc Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Mon, 9 Dec 2024 16:14:26 +0530 Subject: [PATCH 04/23] Check the logic inside of the loop, instead of checking eagerly --- Objects/bytesobject.c | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 9dac36933d4e81..0f123f2d48837a 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -2517,17 +2517,6 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray) assert(PyUnicode_KIND(string) == PyUnicode_1BYTE_KIND); str = PyUnicode_1BYTE_DATA(string); - for (Py_ssize_t i = 0; i < hexlen; i++) { - if (!Py_ISSPACE(str[i])) { - real_len++; - } - } - if (real_len % 2 != 0) { - PyErr_SetString(PyExc_ValueError, - "fromhex() arg must be of even length"); - _PyBytesWriter_Dealloc(&writer); - return NULL; - } /* This overestimates if there are spaces */ buf = _PyBytesWriter_Alloc(&writer, hexlen / 2); @@ -2537,14 +2526,13 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray) end = str + hexlen; while (str < end) { /* skip over spaces in the input */ - if (Py_ISSPACE(*str)) { - do { - str++; - } while (Py_ISSPACE(*str)); - if (str >= end) - break; + while (str < end && Py_ISSPACE(*str)) { + str++; } + if (str >= end) + break; + /* Check first hex digit */ top = _PyLong_DigitValue[*str]; if (top >= 16) { invalid_char = str - PyUnicode_1BYTE_DATA(string); @@ -2552,6 +2540,15 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray) } str++; + /* Check if we have a second digit*/ + if (str >= end || Py_ISSPACE(*str)) { + PyErr_SetString(PyExc_ValueError, + "fromhex() arg must be of even length"); + _PyBytesWriter_Dealloc(&writer); + return NULL; + } + + /* Check second hex digit */ bot = _PyLong_DigitValue[*str]; if (bot >= 16) { invalid_char = str - PyUnicode_1BYTE_DATA(string); From a3ba0e76f08b27db1ffde11fa418a9079599dcd1 Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Mon, 9 Dec 2024 16:15:39 +0530 Subject: [PATCH 05/23] Remove dead variable --- Objects/bytesobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 0f123f2d48837a..e8832e1bf7aad6 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -2490,7 +2490,7 @@ PyObject* _PyBytes_FromHex(PyObject *string, int use_bytearray) { char *buf; - Py_ssize_t hexlen, invalid_char, real_len=0; + Py_ssize_t hexlen, invalid_char; unsigned int top, bot; const Py_UCS1 *str, *end; _PyBytesWriter writer; From ee7947a21314e40d2e1ec4a84fd691a8e967aff3 Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Mon, 9 Dec 2024 16:29:43 +0530 Subject: [PATCH 06/23] Fix a bug in logic --- Objects/bytesobject.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index e8832e1bf7aad6..983eae6677d9ae 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -2540,8 +2540,13 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray) } str++; + /* Skip spaces after first digit */ + while (str < end && Py_ISSPACE(*str)) { + str++; + } + /* Check if we have a second digit*/ - if (str >= end || Py_ISSPACE(*str)) { + if (str >= end) { PyErr_SetString(PyExc_ValueError, "fromhex() arg must be of even length"); _PyBytesWriter_Dealloc(&writer); From 879994e2a6bdd91c5e71910dc6242d2001be7505 Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Mon, 9 Dec 2024 16:34:16 +0530 Subject: [PATCH 07/23] Add some more tests --- Lib/test/test_bytes.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py index 576499517b11c7..92c455efdf5d8c 100644 --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -460,9 +460,10 @@ def test_fromhex(self): self.assertRaises(ValueError, self.type2test.fromhex, '12 \x00 34') # For odd number of character(s) - with self.assertRaises(ValueError) as cm: - self.type2test.fromhex("a") - self.assertIn("fromhex() arg must be of even length", str(cm.exception)) + for value in ("a", "a ", " a"," a ", "aaa", "aaa ", " aaa", " aaa "): + with self.assertRaises(ValueError) as cm: + self.type2test.fromhex(value) + self.assertIn("fromhex() arg must be of even length", str(cm.exception)) for data, pos in ( # invalid first hexadecimal character From ad96b89811ee8a3502a4830a8518d6985ef649f2 Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Mon, 9 Dec 2024 16:40:43 +0530 Subject: [PATCH 08/23] Improve tests --- Lib/test/test_bytes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py index 92c455efdf5d8c..5c45f9c50fc039 100644 --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -460,7 +460,7 @@ def test_fromhex(self): self.assertRaises(ValueError, self.type2test.fromhex, '12 \x00 34') # For odd number of character(s) - for value in ("a", "a ", " a"," a ", "aaa", "aaa ", " aaa", " aaa "): + for value in ("a", "a ", " a"," a ", "a a a", "a a a ", " a a a", " a a a "): with self.assertRaises(ValueError) as cm: self.type2test.fromhex(value) self.assertIn("fromhex() arg must be of even length", str(cm.exception)) From 95744bda2f16f290a8531fb693e3ca3c246a0ce5 Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Mon, 9 Dec 2024 17:37:26 +0530 Subject: [PATCH 09/23] Revert the change that is not necessary --- Objects/bytesobject.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 983eae6677d9ae..879f9af32b4612 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -2526,11 +2526,13 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray) end = str + hexlen; while (str < end) { /* skip over spaces in the input */ - while (str < end && Py_ISSPACE(*str)) { - str++; + if (Py_ISSPACE(*str)) { + do { + str++; + } while (Py_ISSPACE(*str)); + if (str >= end) + break; } - if (str >= end) - break; /* Check first hex digit */ top = _PyLong_DigitValue[*str]; From 6929a4dd582f77ee36664f6c0b9ba41806183606 Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Mon, 9 Dec 2024 17:59:44 +0530 Subject: [PATCH 10/23] Move everthing to error labels --- Objects/bytesobject.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 879f9af32b4612..233c1c0c8b0df9 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -2542,19 +2542,6 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray) } str++; - /* Skip spaces after first digit */ - while (str < end && Py_ISSPACE(*str)) { - str++; - } - - /* Check if we have a second digit*/ - if (str >= end) { - PyErr_SetString(PyExc_ValueError, - "fromhex() arg must be of even length"); - _PyBytesWriter_Dealloc(&writer); - return NULL; - } - /* Check second hex digit */ bot = _PyLong_DigitValue[*str]; if (bot >= 16) { @@ -2569,9 +2556,15 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray) return _PyBytesWriter_Finish(&writer, buf); error: - PyErr_Format(PyExc_ValueError, - "non-hexadecimal number found in " - "fromhex() arg at position %zd", invalid_char); + if (str >= end) { + PyErr_SetString(PyExc_ValueError, + "fromhex() arg must be of even length"); + } + else { + PyErr_Format(PyExc_ValueError, + "non-hexadecimal number found in " + "fromhex() arg at position %zd", invalid_char); + } _PyBytesWriter_Dealloc(&writer); return NULL; } From aa6684bde1db471b3b580ed7b13b8b51720621b3 Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Mon, 9 Dec 2024 18:01:21 +0530 Subject: [PATCH 11/23] Remove comments --- Objects/bytesobject.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 233c1c0c8b0df9..fe0477ffa5ad06 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -2534,7 +2534,6 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray) break; } - /* Check first hex digit */ top = _PyLong_DigitValue[*str]; if (top >= 16) { invalid_char = str - PyUnicode_1BYTE_DATA(string); @@ -2542,7 +2541,6 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray) } str++; - /* Check second hex digit */ bot = _PyLong_DigitValue[*str]; if (bot >= 16) { invalid_char = str - PyUnicode_1BYTE_DATA(string); From bf3ace9a17cc32738467123bd4e22b3c40f55328 Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Mon, 9 Dec 2024 20:21:55 +0530 Subject: [PATCH 12/23] Add tests and update logic --- Lib/test/test_bytes.py | 2 +- Objects/bytesobject.c | 20 +++++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py index 5c45f9c50fc039..44efe45afc0dff 100644 --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -460,7 +460,7 @@ def test_fromhex(self): self.assertRaises(ValueError, self.type2test.fromhex, '12 \x00 34') # For odd number of character(s) - for value in ("a", "a ", " a"," a ", "a a a", "a a a ", " a a a", " a a a "): + for value in ("a", "a ", " a"," a ", "a a a", "aa a ", " aa a", " aaa "): with self.assertRaises(ValueError) as cm: self.type2test.fromhex(value) self.assertIn("fromhex() arg must be of even length", str(cm.exception)) diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index fe0477ffa5ad06..30f232e2dbb231 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -2541,6 +2541,14 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray) } str++; + /* Check if we have a second digit*/ + if (str >= end) { + PyErr_SetString(PyExc_ValueError, + "fromhex() arg must be of even length"); + _PyBytesWriter_Dealloc(&writer); + return NULL; + } + bot = _PyLong_DigitValue[*str]; if (bot >= 16) { invalid_char = str - PyUnicode_1BYTE_DATA(string); @@ -2554,15 +2562,9 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray) return _PyBytesWriter_Finish(&writer, buf); error: - if (str >= end) { - PyErr_SetString(PyExc_ValueError, - "fromhex() arg must be of even length"); - } - else { - PyErr_Format(PyExc_ValueError, - "non-hexadecimal number found in " - "fromhex() arg at position %zd", invalid_char); - } + PyErr_Format(PyExc_ValueError, + "non-hexadecimal number found in " + "fromhex() arg at position %zd", invalid_char); _PyBytesWriter_Dealloc(&writer); return NULL; } From 3588d181dc8c611a094397b754b2d6b830c7b0cc Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Mon, 9 Dec 2024 20:29:46 +0530 Subject: [PATCH 13/23] Update tests --- Lib/test/test_bytes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py index 44efe45afc0dff..400f99ca6810ba 100644 --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -460,7 +460,7 @@ def test_fromhex(self): self.assertRaises(ValueError, self.type2test.fromhex, '12 \x00 34') # For odd number of character(s) - for value in ("a", "a ", " a"," a ", "a a a", "aa a ", " aa a", " aaa "): + for value in ("a", "a ", " a"," a ", "aaa", "aaa ", " aaa", " aaa "): with self.assertRaises(ValueError) as cm: self.type2test.fromhex(value) self.assertIn("fromhex() arg must be of even length", str(cm.exception)) From 504f4edc0ad2214ad309235a9bd1909879de9bf0 Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Mon, 9 Dec 2024 20:38:55 +0530 Subject: [PATCH 14/23] Add tests and update logic --- Objects/bytesobject.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 30f232e2dbb231..832939e5535ae1 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -2541,12 +2541,10 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray) } str++; - /* Check if we have a second digit*/ + /* Check if we have a second digit */ if (str >= end) { - PyErr_SetString(PyExc_ValueError, - "fromhex() arg must be of even length"); - _PyBytesWriter_Dealloc(&writer); - return NULL; + invalid_char = -2; + goto error; } bot = _PyLong_DigitValue[*str]; @@ -2562,9 +2560,14 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray) return _PyBytesWriter_Finish(&writer, buf); error: - PyErr_Format(PyExc_ValueError, - "non-hexadecimal number found in " - "fromhex() arg at position %zd", invalid_char); + if (invalid_char == -2) { + PyErr_SetString(PyExc_ValueError, + "fromhex() arg must be of even length"); + } else { + PyErr_Format(PyExc_ValueError, + "non-hexadecimal number found in " + "fromhex() arg at position %zd", invalid_char); + } _PyBytesWriter_Dealloc(&writer); return NULL; } From 7bab683e1ea5684f97b3e93bb669989afdebd6ac Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Mon, 9 Dec 2024 20:51:27 +0530 Subject: [PATCH 15/23] Change the invalid_char value to -1 --- Objects/bytesobject.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 832939e5535ae1..4f8a48c20c1f7a 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -2543,7 +2543,7 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray) /* Check if we have a second digit */ if (str >= end) { - invalid_char = -2; + invalid_char = -1; goto error; } @@ -2560,7 +2560,7 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray) return _PyBytesWriter_Finish(&writer, buf); error: - if (invalid_char == -2) { + if (invalid_char == -1) { PyErr_SetString(PyExc_ValueError, "fromhex() arg must be of even length"); } else { From 7c819c1bce974ba35d58d176455042b6bbb838e4 Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Mon, 9 Dec 2024 20:58:19 +0530 Subject: [PATCH 16/23] Update test case --- Lib/test/test_bytes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py index 400f99ca6810ba..c2fc13e8db3d5d 100644 --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -460,7 +460,7 @@ def test_fromhex(self): self.assertRaises(ValueError, self.type2test.fromhex, '12 \x00 34') # For odd number of character(s) - for value in ("a", "a ", " a"," a ", "aaa", "aaa ", " aaa", " aaa "): + for value in ("a", "a ", " a"," a ", "aaa", "aaa ", " aaa", " aaa ", " aa a "): with self.assertRaises(ValueError) as cm: self.type2test.fromhex(value) self.assertIn("fromhex() arg must be of even length", str(cm.exception)) From 862bfd578435b0c4d80fc5da0ddc1a628f964447 Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Tue, 10 Dec 2024 12:49:03 +0530 Subject: [PATCH 17/23] gh-127740: Improve error messages as suggested by @hauntsaninja --- Lib/test/test_bytes.py | 4 ++-- Objects/bytesobject.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py index c2fc13e8db3d5d..d3331bbb932da8 100644 --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -460,10 +460,10 @@ def test_fromhex(self): self.assertRaises(ValueError, self.type2test.fromhex, '12 \x00 34') # For odd number of character(s) - for value in ("a", "a ", " a"," a ", "aaa", "aaa ", " aaa", " aaa ", " aa a "): + for value in ("a", "a ", " a"," a ", "aaa", "aaa ", " aaa", " aaa "): with self.assertRaises(ValueError) as cm: self.type2test.fromhex(value) - self.assertIn("fromhex() arg must be of even length", str(cm.exception)) + self.assertIn("fromhex() arg must contain an even number of hexadecimal digits", str(cm.exception)) for data, pos in ( # invalid first hexadecimal character diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 4f8a48c20c1f7a..b59c414c7cbf81 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -2562,7 +2562,7 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray) error: if (invalid_char == -1) { PyErr_SetString(PyExc_ValueError, - "fromhex() arg must be of even length"); + "fromhex() arg must contain an even number of hexadecimal digits"); } else { PyErr_Format(PyExc_ValueError, "non-hexadecimal number found in " From 6cc930541ccd73516086ee2574f63ec04030346e Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Tue, 10 Dec 2024 13:10:41 +0530 Subject: [PATCH 18/23] Update test cases --- Lib/test/test_bytes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py index d3331bbb932da8..32cd178fa3b445 100644 --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -460,7 +460,7 @@ def test_fromhex(self): self.assertRaises(ValueError, self.type2test.fromhex, '12 \x00 34') # For odd number of character(s) - for value in ("a", "a ", " a"," a ", "aaa", "aaa ", " aaa", " aaa "): + for value in ("a", "aaa", "deadbee"): with self.assertRaises(ValueError) as cm: self.type2test.fromhex(value) self.assertIn("fromhex() arg must contain an even number of hexadecimal digits", str(cm.exception)) From c34696e7268a97c29e3015a0f52cdf1d25c782ae Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Tue, 10 Dec 2024 14:51:40 +0530 Subject: [PATCH 19/23] gh-127740: NULL at the end is mapped to 37 --- Objects/bytesobject.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index b59c414c7cbf81..b5819dc88f7948 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -2540,16 +2540,14 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray) goto error; } str++; - - /* Check if we have a second digit */ - if (str >= end) { - invalid_char = -1; - goto error; - } - bot = _PyLong_DigitValue[*str]; if (bot >= 16) { - invalid_char = str - PyUnicode_1BYTE_DATA(string); + /* NULL at the end of the string */ + if (bot == 37){ + invalid_char = -1; + } else { + invalid_char = str - PyUnicode_1BYTE_DATA(string); + } goto error; } str++; From 82762db31f2beb85069f52f17ff46f59bf968552 Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Tue, 10 Dec 2024 14:53:13 +0530 Subject: [PATCH 20/23] gh-127740: Reintroduce the space back --- Objects/bytesobject.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index b5819dc88f7948..474a625143e9a7 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -2540,6 +2540,7 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray) goto error; } str++; + bot = _PyLong_DigitValue[*str]; if (bot >= 16) { /* NULL at the end of the string */ From 6628ea7ee45a5db84fe06069c8bdd7660ecdb073 Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Tue, 10 Dec 2024 15:09:18 +0530 Subject: [PATCH 21/23] gh-127740: Check if we had a second digit --- Objects/bytesobject.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 474a625143e9a7..533089d25cd73a 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -2543,8 +2543,8 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray) bot = _PyLong_DigitValue[*str]; if (bot >= 16) { - /* NULL at the end of the string */ - if (bot == 37){ + /* Check if we had a second digit */ + if (str >= end){ invalid_char = -1; } else { invalid_char = str - PyUnicode_1BYTE_DATA(string); From b20e248f2b8bfe524b8b2d4a2a4a8dd4180c3818 Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Tue, 10 Dec 2024 21:09:41 +0530 Subject: [PATCH 22/23] Add News entry --- .../2024-12-10-21-08-05.gh-issue-127740.0tWC9h.rst | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-12-10-21-08-05.gh-issue-127740.0tWC9h.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-12-10-21-08-05.gh-issue-127740.0tWC9h.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-12-10-21-08-05.gh-issue-127740.0tWC9h.rst new file mode 100644 index 00000000000000..cf175dfcd21893 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-12-10-21-08-05.gh-issue-127740.0tWC9h.rst @@ -0,0 +1,3 @@ +Fix error message in :func:`bytes.fromhex()` when given an odd number of +digits to properly indicate that an even number of hexadecimal digits is +required. From cbf50b438ffc02c75231182135b1c17bef7b18a0 Mon Sep 17 00:00:00 2001 From: Srinivas Reddy Thatiparthy Date: Tue, 10 Dec 2024 22:01:48 +0530 Subject: [PATCH 23/23] Fix lint --- .../2024-12-10-21-08-05.gh-issue-127740.0tWC9h.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-12-10-21-08-05.gh-issue-127740.0tWC9h.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-12-10-21-08-05.gh-issue-127740.0tWC9h.rst index cf175dfcd21893..f614dbb59bdc87 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-12-10-21-08-05.gh-issue-127740.0tWC9h.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-12-10-21-08-05.gh-issue-127740.0tWC9h.rst @@ -1,3 +1,3 @@ -Fix error message in :func:`bytes.fromhex()` when given an odd number of +Fix error message in :func:`bytes.fromhex` when given an odd number of digits to properly indicate that an even number of hexadecimal digits is required.