actually, behave with silent wraparound; results validated by bc(1)

This commit is contained in:
tg 2011-12-11 01:56:43 +00:00
parent 971b153933
commit e18f4d114a
2 changed files with 24 additions and 16 deletions

15
check.t
View File

@ -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: 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: 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 $ # $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 Check division by zero errors out
stdin: stdin:
x=$(echo $((1 / 0))) x=$(echo $((1 / 0)))
echo =$?. echo =$?:$x.
expected-stdout: expected-stdout:
=1. =1:.
expected-stderr-pattern: expected-stderr-pattern:
/.*divisor/ /.*divisor/
--- ---
name: arith-div-intmin-by-minusone name: arith-div-intmin-by-minusone
description: description:
Check division overflow errors out Check division overflow wraps around silently
stdin: stdin:
x=$(echo $((-2147483648 / -1))) echo :$((-2147483648 / -1))_$((-2147483648 % -1)).
echo =$?.
expected-stdout: expected-stdout:
=1. :-2147483648_0.
expected-stderr-pattern:
/.*divisor/
--- ---
name: arith-assop-assoc-1 name: arith-assop-assoc-1
description: description:

25
expr.c
View File

@ -22,7 +22,7 @@
#include "sh.h" #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[] */ /* The order of these enums is constrained by the order of opinfo[] */
enum token { enum token {
@ -343,7 +343,8 @@ evalexpr(Expr_state *es, int prec)
op = es->tok) { op = es->tok) {
exprtoken(es); exprtoken(es);
vasn = vl; 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); vl = intvar(es, vl);
if (IS_ASSIGNOP(op)) { if (IS_ASSIGNOP(op)) {
assign_check(es, op, vasn); 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) } else if (op != O_TERN && op != O_LAND && op != O_LOR)
vr = intvar(es, evalexpr(es, prec - 1)); vr = intvar(es, evalexpr(es, prec - 1));
if ((op == O_DIV || op == O_MOD || op == O_DIVASN || if ((op == O_DIV || op == O_MOD || op == O_DIVASN ||
op == O_MODASN) && (vr->val.i == 0 || (!es->natural && op == O_MODASN) && vr->val.i == 0) {
vr->val.i == -1 && vl->val.i == -2147483648))) {
if (es->noassign) if (es->noassign)
vr->val.i = 1; vr->val.i = 1;
else else
evalerr(es, ET_STR, "invalid divisor"); evalerr(es, ET_STR, "zero divisor");
} }
switch ((int)op) { switch ((int)op) {
case O_TIMES: case O_TIMES:
@ -365,11 +365,22 @@ evalexpr(Expr_state *es, int prec)
break; break;
case O_DIV: case O_DIV:
case O_DIVASN: 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; break;
case O_MOD: case O_MOD:
case O_MODASN: 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; break;
case O_PLUS: case O_PLUS:
case O_PLUSASN: case O_PLUSASN: