From 5bf565e353b73bc87e0b918368dadac701644078 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 4 Apr 2014 00:16:32 +0100 Subject: [PATCH] py: Handle small int power overflow correctly. --- py/mpz.c | 5 ++++- py/runtime.c | 20 ++++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/py/mpz.c b/py/mpz.c index 4a8941e29..21b390996 100644 --- a/py/mpz.c +++ b/py/mpz.c @@ -993,8 +993,11 @@ void mpz_pow_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) { if (mpz_is_odd(n)) { mpz_mul_inpl(dest, dest, x); } - mpz_mul_inpl(x, x, x); n->len = mpn_shr(n->dig, n->dig, n->len, 1); + if (n->len == 0) { + break; + } + mpz_mul_inpl(x, x, x); } mpz_free(x); diff --git a/py/runtime.c b/py/runtime.c index e2e349564..d9e2298c4 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -367,18 +367,34 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "negative power with no float support")); #endif } else { - // TODO check for overflow machine_int_t ans = 1; while (rhs_val > 0) { if (rhs_val & 1) { + machine_int_t old = ans; ans *= lhs_val; + if (ans < old) { + goto power_overflow; + } + } + if (rhs_val == 1) { + break; } - lhs_val *= lhs_val; rhs_val /= 2; + machine_int_t old = lhs_val; + lhs_val *= lhs_val; + if (lhs_val < old) { + goto power_overflow; + } } lhs_val = ans; } break; + + power_overflow: + // use higher precision + lhs = mp_obj_new_int_from_ll(MP_OBJ_SMALL_INT_VALUE(lhs)); + goto generic_binary_op; + case MP_BINARY_OP_LESS: return MP_BOOL(lhs_val < rhs_val); break; case MP_BINARY_OP_MORE: return MP_BOOL(lhs_val > rhs_val); break; case MP_BINARY_OP_LESS_EQUAL: return MP_BOOL(lhs_val <= rhs_val); break;