Skip to content

Commit 5bf565e

Browse files
committed
py: Handle small int power overflow correctly.
1 parent 4b34c76 commit 5bf565e

2 files changed

Lines changed: 22 additions & 3 deletions

File tree

py/mpz.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -993,8 +993,11 @@ void mpz_pow_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
993993
if (mpz_is_odd(n)) {
994994
mpz_mul_inpl(dest, dest, x);
995995
}
996-
mpz_mul_inpl(x, x, x);
997996
n->len = mpn_shr(n->dig, n->dig, n->len, 1);
997+
if (n->len == 0) {
998+
break;
999+
}
1000+
mpz_mul_inpl(x, x, x);
9981001
}
9991002

10001003
mpz_free(x);

py/runtime.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -367,18 +367,34 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
367367
nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "negative power with no float support"));
368368
#endif
369369
} else {
370-
// TODO check for overflow
371370
machine_int_t ans = 1;
372371
while (rhs_val > 0) {
373372
if (rhs_val & 1) {
373+
machine_int_t old = ans;
374374
ans *= lhs_val;
375+
if (ans < old) {
376+
goto power_overflow;
377+
}
378+
}
379+
if (rhs_val == 1) {
380+
break;
375381
}
376-
lhs_val *= lhs_val;
377382
rhs_val /= 2;
383+
machine_int_t old = lhs_val;
384+
lhs_val *= lhs_val;
385+
if (lhs_val < old) {
386+
goto power_overflow;
387+
}
378388
}
379389
lhs_val = ans;
380390
}
381391
break;
392+
393+
power_overflow:
394+
// use higher precision
395+
lhs = mp_obj_new_int_from_ll(MP_OBJ_SMALL_INT_VALUE(lhs));
396+
goto generic_binary_op;
397+
382398
case MP_BINARY_OP_LESS: return MP_BOOL(lhs_val < rhs_val); break;
383399
case MP_BINARY_OP_MORE: return MP_BOOL(lhs_val > rhs_val); break;
384400
case MP_BINARY_OP_LESS_EQUAL: return MP_BOOL(lhs_val <= rhs_val); break;

0 commit comments

Comments
 (0)