diff options
author | Paul Eggert <eggert@cs.ucla.edu> | 2006-06-07 05:52:27 +0000 |
---|---|---|
committer | Paul Eggert <eggert@cs.ucla.edu> | 2006-06-07 05:52:27 +0000 |
commit | dea306fe784789b0d9b7f63cd53f3b492d3a691d (patch) | |
tree | c97a6c6078f12f3c917466e269cc46a4a4a8de34 /src | |
parent | 0038f24b9ac50c6b7888fabc89e7c6096a200056 (diff) | |
download | coreutils-dea306fe784789b0d9b7f63cd53f3b492d3a691d.tar.xz |
(integer_overflow): New function.
(eval4, eval3): Check for integer overflow.
Diffstat (limited to 'src')
-rw-r--r-- | src/expr.c | 38 |
1 files changed, 35 insertions, 3 deletions
diff --git a/src/expr.c b/src/expr.c index c5b1ae87b..ab36350e5 100644 --- a/src/expr.c +++ b/src/expr.c @@ -175,6 +175,13 @@ syntax_error (void) error (EXPR_INVALID, 0, _("syntax error")); } +/* Report an integer overflow for operation OP and exit. */ +static void +integer_overflow (char op) +{ + error (EXPR_FAILURE, ERANGE, "%c", op); +} + int main (int argc, char **argv) { @@ -631,12 +638,26 @@ eval4 (bool evaluate) if (!toarith (l) || !toarith (r)) error (EXPR_INVALID, 0, _("non-numeric argument")); if (fxn == multiply) - val = l->u.i * r->u.i; + { + val = l->u.i * r->u.i; + if (! (l->u.i == 0 || val / l->u.i == r->u.i)) + integer_overflow ('*'); + } else { if (r->u.i == 0) error (EXPR_INVALID, 0, _("division by zero")); - val = fxn == divide ? l->u.i / r->u.i : l->u.i % r->u.i; + if (l->u.i < - INTMAX_MAX && r->u.i == -1) + { + /* Some x86-style hosts erroneously raise an + exception for INT_MIN / -1 and INT_MIN % -1, so + handle these problematic cases specially. */ + if (fxn == divide) + integer_overflow ('/'); + val = 0; + } + else + val = fxn == divide ? l->u.i / r->u.i : l->u.i % r->u.i; } } freev (l); @@ -672,7 +693,18 @@ eval3 (bool evaluate) { if (!toarith (l) || !toarith (r)) error (EXPR_INVALID, 0, _("non-numeric argument")); - val = fxn == plus ? l->u.i + r->u.i : l->u.i - r->u.i; + if (fxn == plus) + { + val = l->u.i + r->u.i; + if ((val < l->u.i) != (r->u.i < 0)) + integer_overflow ('+'); + } + else + { + val = l->u.i - r->u.i; + if ((l->u.i < val) != (r->u.i < 0)) + integer_overflow ('-'); + } } freev (l); freev (r); |