From 34e2788ee8bdc075c997b5698fe55d0b1bdcfd86 Mon Sep 17 00:00:00 2001 From: Arne Goedeke <el@laramies.com> Date: Fri, 11 Jan 2013 15:56:59 +0100 Subject: [PATCH] `%: add overflow checks --- src/bignum.h | 10 ++++++++++ src/operators.c | 46 +++++++++++++++++++++++++++++++++++----------- src/testsuite.in | 2 ++ 3 files changed, 47 insertions(+), 11 deletions(-) diff --git a/src/bignum.h b/src/bignum.h index 4e4f326216..cfbb024625 100644 --- a/src/bignum.h +++ b/src/bignum.h @@ -167,6 +167,16 @@ static INLINE int type ## _SUB_OVERFLOW(type a, type b) { \ int of = 0; \ DO_ ## type ## _SUB_OVERFLOW(a, b, &of); \ return of; \ +} \ +static INLINE int type ## _MOD_OVERFLOW(type a, type b) { \ + return type ## _DIV_OVERFLOW(a, b); \ +} \ +static INLINE type DO_ ## type ## _MOD_OVERFLOW(type a, type b, int * of) { \ + if (type ## _MOD_OVERFLOW(a, b)) { \ + *of = 1; \ + return 0; \ + } \ + return a % b; \ } diff --git a/src/operators.c b/src/operators.c index 7f94cb370e..32f1ca487b 100644 --- a/src/operators.c +++ b/src/operators.c @@ -4231,6 +4231,9 @@ PMOD_EXPORT void o_mod(void) { if(TYPEOF(sp[-2]) != TYPEOF(sp[-1]) && !float_promote()) { +#ifdef AUTO_BIGNUM +do_lfun_modulo: +#endif if(call_lfun(LFUN_MOD, LFUN_RMOD)) return; @@ -4305,28 +4308,49 @@ PMOD_EXPORT void o_mod(void) return; } case T_INT: - if (sp[-1].u.integer == 0) + { + int of = 0; + INT_TYPE a = sp[-2].u.integer, + b = sp[-1].u.integer; + INT_TYPE res; + if (b == 0) OP_MODULO_BY_ZERO_ERROR("`%"); - sp--; - if(sp[-1].u.integer>=0) + if(a>=0) { - if(sp[0].u.integer>=0) + if(b>=0) { - sp[-1].u.integer %= sp[0].u.integer; + res = a % b; }else{ - sp[-1].u.integer=((sp[-1].u.integer+~sp[0].u.integer)%-sp[0].u.integer)-~sp[0].u.integer; + /* res = ((a+~b)%-b)-~b */ + res = DO_INT_TYPE_ADD_OVERFLOW(a, ~b, &of); + res = DO_INT_TYPE_MOD_OVERFLOW(res, b, &of); + res = DO_INT_TYPE_SUB_OVERFLOW(res, ~b, &of); } }else{ - if(sp[0].u.integer>=0) + if(b>=0) { - sp[-1].u.integer=sp[0].u.integer+~((~sp[-1].u.integer) % sp[0].u.integer); + /* res = b+~((~a) % b) */ + res = DO_INT_TYPE_MOD_OVERFLOW(~a, b, &of); + res = DO_INT_TYPE_ADD_OVERFLOW(b, ~res, &of); }else{ - sp[-1].u.integer=-(-sp[-1].u.integer % -sp[0].u.integer); + /* a % b and a % -b are equivalent, if overflow does not + * happen + * res = -(-a % -b) = a % b; */ + res = DO_INT_TYPE_MOD_OVERFLOW(a, b, &of); } } - SET_SVAL_SUBTYPE(sp[-1], NUMBER_NUMBER); +#ifdef AUTO_BIGNUM + if (of) { + stack_swap(); + convert_stack_top_to_bignum(); + stack_swap(); + goto do_lfun_modulo; + } +#endif + sp--; + SET_SVAL(sp[-1], T_INT, NUMBER_NUMBER, integer, res); return; - + } default: PIKE_ERROR("`%", "Bad argument 1.\n", sp, 2); } diff --git a/src/testsuite.in b/src/testsuite.in index f03d6f84fa..e6a656d430 100644 --- a/src/testsuite.in +++ b/src/testsuite.in @@ -8374,6 +8374,8 @@ test_eq(0 ? "a" : 0 ? "b" : 1 ? "c" : 1, "c") // testing overflow checks test_eq(-1 - 0x7fffffff, -0x80000000) +test_eq(Int.NATIVE_MIN % -1, 0) +test_eq(Int.NATIVE_MAX % Int.NATIVE_MIN, -1) // testing indexing test_eq("foo"[0],'f') -- GitLab