arith: Detect overflow in division
@@ -107,7 +107,9 @@ | ||
107 | 107 | __attribute__((nonnull,warn_unused_result)); |
108 | 108 | static long do_long_comparison(atokentype_T ttype, long v1, long v2) |
109 | 109 | __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)); | |
111 | 113 | static long do_double_comparison(atokentype_T ttype, double v1, double v2); |
112 | 114 | static void parse_conditional(evalinfo_T *info, value_T *result) |
113 | 115 | __attribute__((nonnull)); |
@@ -150,9 +152,6 @@ | ||
150 | 152 | __attribute__((nonnull)); |
151 | 153 | static void next_token(evalinfo_T *info) |
152 | 154 | __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)); | |
156 | 155 | static bool long_mul_will_overflow(long v1, long v2) |
157 | 156 | __attribute__((const,warn_unused_result)); |
158 | 157 |
@@ -337,8 +336,6 @@ | ||
337 | 336 | case TT_PLUS: case TT_PLUSEQUAL: |
338 | 337 | case TT_MINUS: case TT_MINUSEQUAL: |
339 | 338 | result->type = coerce_type(info, lhs, rhs); |
340 | - if (fail_if_will_divide_by_zero(ttype, rhs, info, result)) | |
341 | - return false; | |
342 | 339 | switch (result->type) { |
343 | 340 | case VT_LONG: |
344 | 341 | if (!do_long_calculation1(ttype, lhs->v_long, rhs->v_long, |
@@ -349,8 +346,12 @@ | ||
349 | 346 | } |
350 | 347 | break; |
351 | 348 | 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 | + } | |
354 | 355 | break; |
355 | 356 | case VT_VAR: |
356 | 357 | assert(false); |
@@ -410,9 +411,17 @@ | ||
410 | 411 | *result = v1 * v2; |
411 | 412 | return true; |
412 | 413 | 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; | |
413 | 418 | *result = v1 / v2; |
414 | 419 | return true; |
415 | 420 | 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; | |
416 | 425 | *result = v1 % v2; |
417 | 426 | return true; |
418 | 427 | default: |
@@ -422,6 +431,9 @@ | ||
422 | 431 | overflow: |
423 | 432 | xerror(0, Ngt("arithmetic: overflow")); |
424 | 433 | return false; |
434 | +division_by_zero: | |
435 | + xerror(0, Ngt("arithmetic: division by zero")); | |
436 | + return false; | |
425 | 437 | } |
426 | 438 | |
427 | 439 | /* Applies binary operator `ttype' to the given operands `v1' and `v2'. |
@@ -471,24 +483,45 @@ | ||
471 | 483 | } |
472 | 484 | } |
473 | 485 | |
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) | |
477 | 491 | { |
478 | 492 | switch (ttype) { |
479 | 493 | case TT_PLUS: case TT_PLUSEQUAL: |
480 | - return v1 + v2; | |
494 | + *result = v1 + v2; | |
495 | + return true; | |
481 | 496 | case TT_MINUS: case TT_MINUSEQUAL: |
482 | - return v1 - v2; | |
497 | + *result = v1 - v2; | |
498 | + return true; | |
483 | 499 | case TT_ASTER: case TT_ASTEREQUAL: |
484 | - return v1 * v2; | |
500 | + *result = v1 * v2; | |
501 | + return true; | |
485 | 502 | 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; | |
487 | 509 | 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; | |
489 | 516 | default: |
490 | 517 | assert(false); |
491 | 518 | } |
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 | |
492 | 525 | } |
493 | 526 | |
494 | 527 | /* Does double comparison according to the specified operator token. */ |
@@ -1399,46 +1432,6 @@ | ||
1399 | 1432 | } |
1400 | 1433 | } |
1401 | 1434 | |
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 | - | |
1442 | 1435 | /* Tests whether the multiplication of the given two long values will overflow. |
1443 | 1436 | */ |
1444 | 1437 | bool long_mul_will_overflow(long v1, long v2) |