From e18f4d114addeb8d3c661b3dc3bdbb066cf0323c Mon Sep 17 00:00:00 2001 From: tg Date: Sun, 11 Dec 2011 01:56:43 +0000 Subject: [PATCH] actually, behave with silent wraparound; results validated by bc(1) --- check.t | 15 ++++++--------- expr.c | 25 ++++++++++++++++++------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/check.t b/check.t index 656649e..4ede9a5 100644 --- a/check.t +++ b/check.t @@ -1,4 +1,4 @@ -# $MirOS: src/bin/mksh/check.t,v 1.502 2011/12/11 01:35:08 tg Exp $ +# $MirOS: src/bin/mksh/check.t,v 1.503 2011/12/11 01:56:41 tg Exp $ # $OpenBSD: bksl-nl.t,v 1.2 2001/01/28 23:04:56 niklas Exp $ # $OpenBSD: history.t,v 1.5 2001/01/28 23:04:56 niklas Exp $ # $OpenBSD: read.t,v 1.3 2003/03/10 03:48:16 david Exp $ @@ -287,22 +287,19 @@ description: Check division by zero errors out stdin: x=$(echo $((1 / 0))) - echo =$?. + echo =$?:$x. expected-stdout: - =1. + =1:. expected-stderr-pattern: /.*divisor/ --- name: arith-div-intmin-by-minusone description: - Check division overflow errors out + Check division overflow wraps around silently stdin: - x=$(echo $((-2147483648 / -1))) - echo =$?. + echo :$((-2147483648 / -1))_$((-2147483648 % -1)). expected-stdout: - =1. -expected-stderr-pattern: - /.*divisor/ + :-2147483648_0. --- name: arith-assop-assoc-1 description: diff --git a/expr.c b/expr.c index d1fada2..f09e337 100644 --- a/expr.c +++ b/expr.c @@ -22,7 +22,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.50 2011/12/11 01:35:10 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.51 2011/12/11 01:56:43 tg Exp $"); /* The order of these enums is constrained by the order of opinfo[] */ enum token { @@ -343,7 +343,8 @@ evalexpr(Expr_state *es, int prec) op = es->tok) { exprtoken(es); vasn = vl; - if (op != O_ASN) /* vl may not have a value yet */ + if (op != O_ASN) + /* vl may not have a value yet */ vl = intvar(es, vl); if (IS_ASSIGNOP(op)) { assign_check(es, op, vasn); @@ -351,12 +352,11 @@ evalexpr(Expr_state *es, int prec) } else if (op != O_TERN && op != O_LAND && op != O_LOR) vr = intvar(es, evalexpr(es, prec - 1)); if ((op == O_DIV || op == O_MOD || op == O_DIVASN || - op == O_MODASN) && (vr->val.i == 0 || (!es->natural && - vr->val.i == -1 && vl->val.i == -2147483648))) { + op == O_MODASN) && vr->val.i == 0) { if (es->noassign) vr->val.i = 1; else - evalerr(es, ET_STR, "invalid divisor"); + evalerr(es, ET_STR, "zero divisor"); } switch ((int)op) { case O_TIMES: @@ -365,11 +365,22 @@ evalexpr(Expr_state *es, int prec) break; case O_DIV: case O_DIVASN: - res = bivui(vl, /, vr); + if (!es->natural && vr->val.i == -1 && + vl->val.i == ((mksh_ari_t)1 << 31)) { + /* -2147483648 / -1 = 2147483648 */ + /* 80000000 / FFFFFFFF = 80000000 */ + res = ((mksh_ari_t)1 << 31); + } else + res = bivui(vl, /, vr); break; case O_MOD: case O_MODASN: - res = bivui(vl, %, vr); + if (!es->natural && vr->val.i == -1 && + vl->val.i == ((mksh_ari_t)1 << 31)) { + /* -2147483648 % -1 = 0 */ + res = 0; + } else + res = bivui(vl, %, vr); break; case O_PLUS: case O_PLUSASN: