• R/O
  • SSH
  • HTTPS

yash: 提交


Commit MetaInfo

修訂4192 (tree)
時間2022-08-14 23:53:41
作者magicant

Log Message

arith: Detect overflow in +, -, and *

Change Summary

差異

--- yash/branches/arith-error/arith.c (revision 4191)
+++ yash/branches/arith-error/arith.c (revision 4192)
@@ -153,6 +153,8 @@
153153 static bool fail_if_will_divide_by_zero(
154154 atokentype_T op, const value_T *rhs, evalinfo_T *info, value_T *result)
155155 __attribute__((nonnull));
156+static bool long_mul_will_overflow(long v1, long v2)
157+ __attribute__((const,warn_unused_result));
156158
157159
158160 /* Evaluates the specified string as an arithmetic expression.
@@ -393,12 +395,18 @@
393395 {
394396 switch (ttype) {
395397 case TT_PLUS: case TT_PLUSEQUAL:
398+ if (v2 >= 0 ? LONG_MAX - v2 < v1 : v1 < LONG_MIN - v2)
399+ goto overflow;
396400 *result = v1 + v2;
397401 return true;
398402 case TT_MINUS: case TT_MINUSEQUAL:
403+ if (v2 < 0 ? LONG_MAX + v2 < v1 : v1 < LONG_MIN + v2)
404+ goto overflow;
399405 *result = v1 - v2;
400406 return true;
401407 case TT_ASTER: case TT_ASTEREQUAL:
408+ if (long_mul_will_overflow(v1, v2))
409+ goto overflow;
402410 *result = v1 * v2;
403411 return true;
404412 case TT_SLASH: case TT_SLASHEQUAL:
@@ -410,6 +418,10 @@
410418 default:
411419 assert(false);
412420 }
421+
422+overflow:
423+ xerror(0, Ngt("arithmetic: overflow"));
424+ return false;
413425 }
414426
415427 /* Applies binary operator `ttype' to the given operands `v1' and `v2'.
@@ -1427,4 +1439,23 @@
14271439 return true;
14281440 }
14291441
1442+/* Tests whether the multiplication of the given two long values will overflow.
1443+ */
1444+bool long_mul_will_overflow(long v1, long v2)
1445+{
1446+ if (v1 == 0 || v1 == 1 || v2 == 0 || v2 == 1)
1447+ return false;
1448+#if LONG_MIN < -LONG_MAX
1449+ if (v1 == LONG_MIN || v2 == LONG_MIN)
1450+ return true;
1451+#endif
1452+ unsigned long u1 = labs(v1), u2 = labs(v2);
1453+ unsigned long prod = u1 * u2;
1454+#if LONG_MIN < -LONG_MAX
1455+ if (prod == (unsigned long) LONG_MIN)
1456+ return ((v1 >= 0) == (v2 >= 0)) || prod / u2 != u1;
1457+#endif
1458+ return (prod & (unsigned long) LONG_MAX) / u2 != u1;
1459+}
1460+
14301461 /* vim: set ts=8 sts=4 sw=4 noet tw=80: */
Show on old repository browser