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 <jepler@gmail.com>
This commit is contained in:
Jeff Epler 2025-06-11 19:32:28 +02:00
parent 2ce63b1420
commit 71a23bc9a0
3 changed files with 24 additions and 4 deletions

View file

@ -475,6 +475,18 @@ static mp_obj_t extra_coverage(void) {
mp_int_t value_signed;
mpz_as_int_checked(&mpz, &value_signed);
mp_printf(&mp_plat_print, "%d\n", (int)value_signed);
// hash the zero mpz integer
mpz_set_from_int(&mpz, 0);
mp_printf(&mp_plat_print, "%d\n", mpz_hash(&mpz));
// convert the mpz zero integer to int
mp_printf(&mp_plat_print, "%d\n", mpz_as_int_checked(&mpz, &value_signed));
mp_printf(&mp_plat_print, "%d\n", value_signed);
// mpz_set_from_float with 0 as argument
mpz_set_from_float(&mpz, 0);
mp_printf(&mp_plat_print, "%f\n", mpz_as_float(&mpz));
}
// runtime utils

View file

@ -1537,7 +1537,8 @@ mp_int_t mpz_hash(const mpz_t *z) {
mp_uint_t val = 0;
mpz_dig_t *d = z->dig + z->len;
while (d-- > z->dig) {
while (d > z->dig) {
d--;
val = (val << DIG_SIZE) | *d;
}
@ -1552,11 +1553,12 @@ bool mpz_as_int_checked(const mpz_t *i, mp_int_t *value) {
mp_uint_t val = 0;
mpz_dig_t *d = i->dig + i->len;
while (d-- > i->dig) {
while (d > i->dig) {
if (val > (~(MP_OBJ_WORD_MSBIT_HIGH) >> DIG_SIZE)) {
// will overflow
return false;
}
d--;
val = (val << DIG_SIZE) | *d;
}
@ -1577,11 +1579,12 @@ bool mpz_as_uint_checked(const mpz_t *i, mp_uint_t *value) {
mp_uint_t val = 0;
mpz_dig_t *d = i->dig + i->len;
while (d-- > i->dig) {
while (d > i->dig) {
if (val > (~(MP_OBJ_WORD_MSBIT_HIGH) >> (DIG_SIZE - 1))) {
// will overflow
return false;
}
d--;
val = (val << DIG_SIZE) | *d;
}
@ -1642,7 +1645,8 @@ mp_float_t mpz_as_float(const mpz_t *i) {
mp_float_t val = 0;
mpz_dig_t *d = i->dig + i->len;
while (d-- > i->dig) {
while (d > i->dig) {
d--;
val = val * DIG_BASE + *d;
}

View file

@ -89,6 +89,10 @@ data
12345
6
-1
0
1
0
0.000000
# runtime utils
TypeError: unsupported type for __abs__: 'str'
TypeError: unsupported types for __divmod__: 'str', 'str'