• R/O
  • SSH
  • HTTPS

yash: 提交


Commit MetaInfo

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

Log Message

arith: Detect overflow in division

Change Summary

差異

--- yash/branches/arith-error/arith.c (revision 4192)
+++ yash/branches/arith-error/arith.c (revision 4193)
@@ -107,7 +107,9 @@
107107 __attribute__((nonnull,warn_unused_result));
108108 static long do_long_comparison(atokentype_T ttype, long v1, long v2)
109109 __attribute__((const,warn_unused_result));
110-static double do_double_calculation(atokentype_T ttype, double v1, double v2);
110+static bool do_double_calculation(
111+ atokentype_T ttype, double v1, double v2, double *result)
112+ __attribute__((nonnull,warn_unused_result));
111113 static long do_double_comparison(atokentype_T ttype, double v1, double v2);
112114 static void parse_conditional(evalinfo_T *info, value_T *result)
113115 __attribute__((nonnull));
@@ -150,9 +152,6 @@
150152 __attribute__((nonnull));
151153 static void next_token(evalinfo_T *info)
152154 __attribute__((nonnull));
153-static bool fail_if_will_divide_by_zero(
154- atokentype_T op, const value_T *rhs, evalinfo_T *info, value_T *result)
155- __attribute__((nonnull));
156155 static bool long_mul_will_overflow(long v1, long v2)
157156 __attribute__((const,warn_unused_result));
158157
@@ -337,8 +336,6 @@
337336 case TT_PLUS: case TT_PLUSEQUAL:
338337 case TT_MINUS: case TT_MINUSEQUAL:
339338 result->type = coerce_type(info, lhs, rhs);
340- if (fail_if_will_divide_by_zero(ttype, rhs, info, result))
341- return false;
342339 switch (result->type) {
343340 case VT_LONG:
344341 if (!do_long_calculation1(ttype, lhs->v_long, rhs->v_long,
@@ -349,8 +346,12 @@
349346 }
350347 break;
351348 case VT_DOUBLE:
352- result->v_double = do_double_calculation(
353- ttype, lhs->v_double, rhs->v_double);
349+ if (!do_double_calculation(ttype, lhs->v_double,
350+ rhs->v_double, &result->v_double)) {
351+ info->error = true;
352+ result->type = VT_INVALID;
353+ return false;
354+ }
354355 break;
355356 case VT_VAR:
356357 assert(false);
@@ -410,9 +411,17 @@
410411 *result = v1 * v2;
411412 return true;
412413 case TT_SLASH: case TT_SLASHEQUAL:
414+ if (v2 == 0)
415+ goto division_by_zero;
416+ if (v1 == LONG_MIN && v2 == -1)
417+ goto overflow;
413418 *result = v1 / v2;
414419 return true;
415420 case TT_PERCENT: case TT_PERCENTEQUAL:
421+ if (v2 == 0)
422+ goto division_by_zero;
423+ if (v1 == LONG_MIN && v2 == -1)
424+ goto overflow;
416425 *result = v1 % v2;
417426 return true;
418427 default:
@@ -422,6 +431,9 @@
422431 overflow:
423432 xerror(0, Ngt("arithmetic: overflow"));
424433 return false;
434+division_by_zero:
435+ xerror(0, Ngt("arithmetic: division by zero"));
436+ return false;
425437 }
426438
427439 /* Applies binary operator `ttype' to the given operands `v1' and `v2'.
@@ -471,24 +483,45 @@
471483 }
472484 }
473485
474-/* Does unary or binary double calculation according to the specified operator
475- * token. */
476-double do_double_calculation(atokentype_T ttype, double v1, double v2)
486+/* Applies binary operator `ttype' to the given operands `v1' and `v2'.
487+ * If successful, assigns the result to `*result' and returns true.
488+ * Otherwise, prints an error message and returns false. */
489+bool do_double_calculation(
490+ atokentype_T ttype, double v1, double v2, double *result)
477491 {
478492 switch (ttype) {
479493 case TT_PLUS: case TT_PLUSEQUAL:
480- return v1 + v2;
494+ *result = v1 + v2;
495+ return true;
481496 case TT_MINUS: case TT_MINUSEQUAL:
482- return v1 - v2;
497+ *result = v1 - v2;
498+ return true;
483499 case TT_ASTER: case TT_ASTEREQUAL:
484- return v1 * v2;
500+ *result = v1 * v2;
501+ return true;
485502 case TT_SLASH: case TT_SLASHEQUAL:
486- return v1 / v2;
503+#if DOUBLE_DIVISION_BY_ZERO_ERROR
504+ if (v2 == 0.0)
505+ goto division_by_zero;
506+#endif
507+ *result = v1 / v2;
508+ return true;
487509 case TT_PERCENT: case TT_PERCENTEQUAL:
488- return fmod(v1, v2);
510+#if DOUBLE_DIVISION_BY_ZERO_ERROR
511+ if (v2 == 0.0)
512+ goto division_by_zero;
513+#endif
514+ *result = fmod(v1, v2);
515+ return true;
489516 default:
490517 assert(false);
491518 }
519+
520+#if DOUBLE_DIVISION_BY_ZERO_ERROR
521+division_by_zero:
522+ xerror(0, Ngt("arithmetic: division by zero"));
523+ return false;
524+#endif
492525 }
493526
494527 /* Does double comparison according to the specified operator token. */
@@ -1399,46 +1432,6 @@
13991432 }
14001433 }
14011434
1402-/* If `op' is a division operator and `rhs' is zero, then prints an error
1403- * message, sets `info->error' to true, sets `result->type' to VT_INVALID, and
1404- * returns true. Otherwise, just returns false.
1405- * `rhs->type' must not be VT_VAR. */
1406-bool fail_if_will_divide_by_zero(
1407- atokentype_T op, const value_T *rhs, evalinfo_T *info, value_T *result)
1408-{
1409- switch (op) {
1410- case TT_SLASH:
1411- case TT_SLASHEQUAL:
1412- case TT_PERCENT:
1413- case TT_PERCENTEQUAL:
1414- switch (rhs->type) {
1415- case VT_LONG:
1416- if (rhs->v_long == 0)
1417- goto fail;
1418- break;
1419- case VT_DOUBLE:
1420-#if DOUBLE_DIVISION_BY_ZERO_ERROR
1421- if (rhs->v_double == 0.0)
1422- goto fail;
1423-#endif
1424- break;
1425- case VT_VAR:
1426- assert(false);
1427- case VT_INVALID:
1428- break;
1429- }
1430- /* falls through */
1431- default:
1432- return false;
1433- }
1434-
1435-fail:
1436- xerror(0, Ngt("arithmetic: division by zero"));
1437- info->error = true;
1438- result->type = VT_INVALID;
1439- return true;
1440-}
1441-
14421435 /* Tests whether the multiplication of the given two long values will overflow.
14431436 */
14441437 bool long_mul_will_overflow(long v1, long v2)
Show on old repository browser