Skip to content

Commit 0ef5ede

Browse files
jeplerdpgeorge
authored andcommitted
py/mpz: Avoid undefined behavior decrementing NULL.
In the case where an mpz number is zero, its `len` is 0 and its `dig` is NULL. In that case, decrementing NULL via `d--` is undefined behavior according to the C specification. Restructuring the loops in this way avoids undefined behavior. Also, ensure that these cases are tested in the coverage test. This doesn't make much difference now, but would otherwise cause errors later when the undefined behavior sanitizer is employed in CI. Signed-off-by: Jeff Epler <[email protected]>
1 parent 42404b5 commit 0ef5ede

File tree

3 files changed

+24
-4
lines changed

3 files changed

+24
-4
lines changed

ports/unix/coverage.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,18 @@ static mp_obj_t extra_coverage(void) {
475475
mp_int_t value_signed;
476476
mpz_as_int_checked(&mpz, &value_signed);
477477
mp_printf(&mp_plat_print, "%d\n", (int)value_signed);
478+
479+
// hash the zero mpz integer
480+
mpz_set_from_int(&mpz, 0);
481+
mp_printf(&mp_plat_print, "%d\n", mpz_hash(&mpz));
482+
483+
// convert the mpz zero integer to int
484+
mp_printf(&mp_plat_print, "%d\n", mpz_as_int_checked(&mpz, &value_signed));
485+
mp_printf(&mp_plat_print, "%d\n", value_signed);
486+
487+
// mpz_set_from_float with 0 as argument
488+
mpz_set_from_float(&mpz, 0);
489+
mp_printf(&mp_plat_print, "%f\n", mpz_as_float(&mpz));
478490
}
479491

480492
// runtime utils

py/mpz.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1537,7 +1537,8 @@ mp_int_t mpz_hash(const mpz_t *z) {
15371537
mp_uint_t val = 0;
15381538
mpz_dig_t *d = z->dig + z->len;
15391539

1540-
while (d-- > z->dig) {
1540+
while (d > z->dig) {
1541+
d--;
15411542
val = (val << DIG_SIZE) | *d;
15421543
}
15431544

@@ -1552,11 +1553,12 @@ bool mpz_as_int_checked(const mpz_t *i, mp_int_t *value) {
15521553
mp_uint_t val = 0;
15531554
mpz_dig_t *d = i->dig + i->len;
15541555

1555-
while (d-- > i->dig) {
1556+
while (d > i->dig) {
15561557
if (val > (~(MP_OBJ_WORD_MSBIT_HIGH) >> DIG_SIZE)) {
15571558
// will overflow
15581559
return false;
15591560
}
1561+
d--;
15601562
val = (val << DIG_SIZE) | *d;
15611563
}
15621564

@@ -1577,11 +1579,12 @@ bool mpz_as_uint_checked(const mpz_t *i, mp_uint_t *value) {
15771579
mp_uint_t val = 0;
15781580
mpz_dig_t *d = i->dig + i->len;
15791581

1580-
while (d-- > i->dig) {
1582+
while (d > i->dig) {
15811583
if (val > (~(MP_OBJ_WORD_MSBIT_HIGH) >> (DIG_SIZE - 1))) {
15821584
// will overflow
15831585
return false;
15841586
}
1587+
d--;
15851588
val = (val << DIG_SIZE) | *d;
15861589
}
15871590

@@ -1642,7 +1645,8 @@ mp_float_t mpz_as_float(const mpz_t *i) {
16421645
mp_float_t val = 0;
16431646
mpz_dig_t *d = i->dig + i->len;
16441647

1645-
while (d-- > i->dig) {
1648+
while (d > i->dig) {
1649+
d--;
16461650
val = val * DIG_BASE + *d;
16471651
}
16481652

tests/ports/unix/extra_coverage.py.exp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ data
8989
12345
9090
6
9191
-1
92+
0
93+
1
94+
0
95+
0.000000
9296
# runtime utils
9397
TypeError: unsupported type for __abs__: 'str'
9498
TypeError: unsupported types for __divmod__: 'str', 'str'

0 commit comments

Comments
 (0)