Skip to content

Commit 66df30d

Browse files
[3.14] gh-158583: Fix uninitialized memory read in bytes.fromhex() (GH-158584) (#158692)
gh-158583: Fix uninitialized memory read in bytes.fromhex() (GH-158584) (cherry picked from commit 9d22a53) Co-authored-by: Victor Stinner <vstinner@python.org>
1 parent a157420 commit 66df30d

3 files changed

Lines changed: 21 additions & 8 deletions

File tree

‎Lib/test/test_bytes.py‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,15 @@ def test_fromhex(self):
508508
self.type2test.fromhex(data)
509509
self.assertIn('at position %s' % pos, str(cm.exception))
510510

511+
# gh-158583: Check for out of bounds reads (uninitialized bytes).
512+
# Create an array from a list to not overallocate.
513+
a = array.array('B', list(b'1234 ')) # Py_ISSPACE() loop
514+
self.assertEqual(self.type2test.fromhex(a), b'\x12\x34')
515+
516+
a = array.array('B', list(b'12345')) # Missing second digit
517+
with self.assertRaises(ValueError):
518+
self.type2test.fromhex(a)
519+
511520
def test_hex(self):
512521
self.assertRaises(TypeError, self.type2test.hex)
513522
self.assertRaises(TypeError, self.type2test.hex, 1)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
:meth:`bytes.fromhex` and :meth:`bytearray.fromhex`: Fix uninitialized
2+
memory read. Patch by Victor Stinner.

‎Objects/bytesobject.c‎

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2577,33 +2577,35 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray)
25772577
if (Py_ISSPACE(*str)) {
25782578
do {
25792579
str++;
2580+
if (str >= end) {
2581+
goto done;
2582+
}
25802583
} while (Py_ISSPACE(*str));
2581-
if (str >= end)
2582-
break;
25832584
}
25842585

25852586
top = _PyLong_DigitValue[*str];
25862587
if (top >= 16) {
25872588
invalid_char = str - start;
25882589
goto error;
25892590
}
2591+
25902592
str++;
2593+
if (str >= end) {
2594+
invalid_char = -1;
2595+
goto error;
2596+
}
25912597

25922598
bot = _PyLong_DigitValue[*str];
25932599
if (bot >= 16) {
2594-
/* Check if we had a second digit */
2595-
if (str >= end){
2596-
invalid_char = -1;
2597-
} else {
2598-
invalid_char = str - start;
2599-
}
2600+
invalid_char = str - start;
26002601
goto error;
26012602
}
26022603
str++;
26032604

26042605
*buf++ = (unsigned char)((top << 4) + bot);
26052606
}
26062607

2608+
done:
26072609
if (view.obj != NULL) {
26082610
PyBuffer_Release(&view);
26092611
}

0 commit comments

Comments
 (0)