https://github.com/python/cpython/commit/9d22a5334bd5273962adceeb697a1337e9a0ca21
commit: 9d22a5334bd5273962adceeb697a1337e9a0ca21
branch: main
author: Victor Stinner <[email protected]>
committer: vstinner <[email protected]>
date: 2026-10-03T23:51:37Z
summary:

gh-158583: Fix uninitialized memory read in bytes.fromhex() (#158584)

files:
A 
Misc/NEWS.d/next/Core_and_Builtins/2026-10-03-16-14-26.gh-issue-158583.7EUMvS.rst
M Lib/test/test_bytes.py
M Objects/bytesobject.c

diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py
index ea0a54dd5e1d35..0f2eec38631213 100644
--- a/Lib/test/test_bytes.py
+++ b/Lib/test/test_bytes.py
@@ -518,6 +518,15 @@ def test_fromhex(self):
                 self.type2test.fromhex(data)
             self.assertIn('at position %s' % pos, str(cm.exception))
 
+        # gh-158583: Check for out of bounds reads (uninitialized bytes).
+        # Create an array from a list to not overallocate.
+        a = array.array('B', list(b'1234  '))  # Py_ISSPACE() loop
+        self.assertEqual(self.type2test.fromhex(a), b'\x12\x34')
+
+        a = array.array('B', list(b'12345'))  # Missing second digit
+        with self.assertRaises(ValueError):
+            self.type2test.fromhex(a)
+
     def test_hex(self):
         self.assertRaises(TypeError, self.type2test.hex)
         self.assertRaises(TypeError, self.type2test.hex, 1)
diff --git 
a/Misc/NEWS.d/next/Core_and_Builtins/2026-10-03-16-14-26.gh-issue-158583.7EUMvS.rst
 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-10-03-16-14-26.gh-issue-158583.7EUMvS.rst
new file mode 100644
index 00000000000000..c94fcc58add88c
--- /dev/null
+++ 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-10-03-16-14-26.gh-issue-158583.7EUMvS.rst
@@ -0,0 +1,2 @@
+:meth:`bytes.fromhex` and :meth:`bytearray.fromhex`: Fix uninitialized
+memory read. Patch by Victor Stinner.
diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c
index ac3a3340ec3201..e7bc465a87f4a0 100644
--- a/Objects/bytesobject.c
+++ b/Objects/bytesobject.c
@@ -2702,9 +2702,10 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray)
         if (Py_ISSPACE(*str)) {
             do {
                 str++;
+                if (str >= end) {
+                    goto done;
+                }
             } while (Py_ISSPACE(*str));
-            if (str >= end)
-                break;
         }
 
         top = _PyLong_DigitValue[*str];
@@ -2712,16 +2713,16 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray)
             invalid_char = str - start;
             goto error;
         }
+
         str++;
+        if (str >= end) {
+            invalid_char = -1;
+            goto error;
+        }
 
         bot = _PyLong_DigitValue[*str];
         if (bot >= 16) {
-            /* Check if we had a second digit */
-            if (str >= end){
-                invalid_char = -1;
-            } else {
-                invalid_char = str - start;
-            }
+            invalid_char = str - start;
             goto error;
         }
         str++;
@@ -2729,6 +2730,7 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray)
         *buf++ = (unsigned char)((top << 4) + bot);
     }
 
+  done:
     if (view.obj != NULL) {
        PyBuffer_Release(&view);
     }

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to