aboutsummaryrefslogtreecommitdiff
path: root/bin/expr
diff options
context:
space:
mode:
authorStefan Eßer <se@FreeBSD.org>2015-01-27 18:04:41 +0000
committerStefan Eßer <se@FreeBSD.org>2015-01-27 18:04:41 +0000
commit8da97f00573902efb70b1732b550edacf673fef5 (patch)
tree86ce4c17b6bfb4b31eef245e89c775c6b500e9a0 /bin/expr
parentb489a49fc0b64eab08d5af8f6f173bf47fe8e1fc (diff)
Notes
Diffstat (limited to 'bin/expr')
-rw-r--r--bin/expr/expr.y20
1 files changed, 16 insertions, 4 deletions
diff --git a/bin/expr/expr.y b/bin/expr/expr.y
index 1856ec84d0f7..0ddf3990d2a8 100644
--- a/bin/expr/expr.y
+++ b/bin/expr/expr.y
@@ -444,14 +444,26 @@ op_minus(struct val *a, struct val *b)
return (r);
}
+/*
+ * We depend on undefined behaviour giving a result (in r).
+ * To test this result, pass it as volatile. This prevents
+ * optimizing away of the test based on the undefined behaviour.
+ */
void
-assert_times(intmax_t a, intmax_t b, intmax_t r)
+assert_times(intmax_t a, intmax_t b, volatile intmax_t r)
{
/*
- * if first operand is 0, no overflow is possible,
- * else result of division test must match second operand
+ * If the first operand is 0, no overflow is possible,
+ * else the result of the division test must match the
+ * second operand.
+ *
+ * Be careful to avoid overflow in the overflow test, as
+ * in assert_div(). Overflow in division would kill us
+ * with a SIGFPE before getting the test wrong. In old
+ * buggy versions, optimization used to give a null test
+ * instead of a SIGFPE.
*/
- if (a != 0 && r / a != b)
+ if ((a == -1 && b == INTMAX_MIN) || (a != 0 && r / a != b))
errx(ERR_EXIT, "overflow");
}