Skip to content

Commit 1acabab

Browse files
gh-141370: Fix undefined behavior when using Py_ABS()
1 parent 4885ecf commit 1acabab

File tree

5 files changed

+41
-3
lines changed

5 files changed

+41
-3
lines changed

Lib/test/test_bytes.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,17 @@ def test_hex_separator_basics(self):
549549
self.assertEqual(three_bytes.hex(':', 2), 'b9:01ef')
550550
self.assertEqual(three_bytes.hex(':', 1), 'b9:01:ef')
551551
self.assertEqual(three_bytes.hex('*', -2), 'b901*ef')
552+
self.assertEqual(three_bytes.hex(sep=':', bytes_per_sep=2), 'b9:01ef')
553+
self.assertEqual(three_bytes.hex(sep='*', bytes_per_sep=-2), 'b901*ef')
554+
for bytes_per_sep in 3, -3, 2**31-1, -(2**31-1):
555+
with self.subTest(bytes_per_sep=bytes_per_sep):
556+
self.assertEqual(three_bytes.hex(':', bytes_per_sep), 'b901ef')
557+
for bytes_per_sep in 2**31, -2**31, 2**1000, -2**1000:
558+
with self.subTest(bytes_per_sep=bytes_per_sep):
559+
try:
560+
self.assertEqual(three_bytes.hex(':', bytes_per_sep), 'b901ef')
561+
except OverflowError:
562+
pass
552563

553564
value = b'{s\005\000\000\000worldi\002\000\000\000s\005\000\000\000helloi\001\000\000\0000'
554565
self.assertEqual(value.hex('.', 8), '7b7305000000776f.726c646902000000.730500000068656c.6c6f690100000030')

Lib/test/test_marshal.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ def test_ints(self):
4343
for expected in (-n, n):
4444
self.helper(expected)
4545
n = n >> 1
46+
n = 1 << 100
47+
while n:
48+
for expected in (-n, -n+1, n-1, n):
49+
self.helper(expected)
50+
n = n >> 1
4651

4752
def test_int64(self):
4853
# Simulate int marshaling with TYPE_INT64.

Lib/test/test_memoryview.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,25 @@ def test_memoryview_hex(self):
600600
m2 = m1[::-1]
601601
self.assertEqual(m2.hex(), '30' * 200000)
602602

603+
def test_memoryview_hex_separator(self):
604+
x = bytes(range(97, 102))
605+
m1 = memoryview(x)
606+
m2 = m1[::-1]
607+
self.assertEqual(m2.hex(':'), '65:64:63:62:61')
608+
self.assertEqual(m2.hex(':', 2), '65:6463:6261')
609+
self.assertEqual(m2.hex(':', -2), '6564:6362:61')
610+
self.assertEqual(m2.hex(sep=':', bytes_per_sep=2), '65:6463:6261')
611+
self.assertEqual(m2.hex(sep=':', bytes_per_sep=-2), '6564:6362:61')
612+
for bytes_per_sep in 5, -5, 2**31-1, -(2**31-1):
613+
with self.subTest(bytes_per_sep=bytes_per_sep):
614+
self.assertEqual(m2.hex(':', bytes_per_sep), '6564636261')
615+
for bytes_per_sep in 2**31, -2**31, 2**1000, -2**1000:
616+
with self.subTest(bytes_per_sep=bytes_per_sep):
617+
try:
618+
self.assertEqual(m2.hex(':', bytes_per_sep), '6564636261')
619+
except OverflowError:
620+
pass
621+
603622
def test_copy(self):
604623
m = memoryview(b'abc')
605624
with self.assertRaises(TypeError):

Python/marshal.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,9 @@ w_PyLong(const PyLongObject *ob, char flag, WFILE *p)
310310
}
311311
if (!long_export.digits) {
312312
int8_t sign = long_export.value < 0 ? -1 : 1;
313-
uint64_t abs_value = Py_ABS(long_export.value);
313+
uint64_t abs_value = long_export.value < -INT64_MAX
314+
? (uint64_t)INT64_MAX + (uint64_t)-(long_export.value + INT64_MAX)
315+
: (uint64_t)Py_ABS(long_export.value);
314316
uint64_t d = abs_value;
315317
long l = 0;
316318

Python/pystrhex.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,9 @@ static PyObject *_Py_strhex_impl(const char* argbuf, const Py_ssize_t arglen,
4242
else {
4343
bytes_per_sep_group = 0;
4444
}
45-
46-
unsigned int abs_bytes_per_sep = Py_ABS(bytes_per_sep_group);
45+
unsigned int abs_bytes_per_sep = (bytes_per_sep_group < -INT_MAX)
46+
? (unsigned int)INT_MAX + (unsigned int)-(bytes_per_sep_group + INT_MAX)
47+
: (unsigned int)Py_ABS(bytes_per_sep_group);
4748
Py_ssize_t resultlen = 0;
4849
if (bytes_per_sep_group && arglen > 0) {
4950
/* How many sep characters we'll be inserting. */

0 commit comments

Comments
 (0)