diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2014-11-18 14:32:58 +0100 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2014-11-18 14:32:58 +0100 |
| commit | 8a475def9e3e21f780ebcf07dd607b26ceb00ea8 (patch) | |
| tree | 3f09f0533abe2126d00146448eb34f333b8c7564 /shell | |
| parent | 08a5dab181fa4c28b7636c35021308e1e12e7b59 (diff) | |
| download | busybox-w32-8a475def9e3e21f780ebcf07dd607b26ceb00ea8.tar.gz busybox-w32-8a475def9e3e21f780ebcf07dd607b26ceb00ea8.tar.bz2 busybox-w32-8a475def9e3e21f780ebcf07dd607b26ceb00ea8.zip | |
ash,hush: do not segfault on $((2**63 / -1))
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell')
| -rw-r--r-- | shell/math.c | 27 |
1 files changed, 23 insertions, 4 deletions
diff --git a/shell/math.c b/shell/math.c index 3da151137..e7565ebf2 100644 --- a/shell/math.c +++ b/shell/math.c | |||
| @@ -415,10 +415,29 @@ arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_ | |||
| 415 | } | 415 | } |
| 416 | else if (right_side_val == 0) | 416 | else if (right_side_val == 0) |
| 417 | return "divide by zero"; | 417 | return "divide by zero"; |
| 418 | else if (op == TOK_DIV || op == TOK_DIV_ASSIGN) | 418 | else if (op == TOK_DIV || op == TOK_DIV_ASSIGN |
| 419 | rez /= right_side_val; | 419 | || op == TOK_REM || op == TOK_REM_ASSIGN) { |
| 420 | else if (op == TOK_REM || op == TOK_REM_ASSIGN) | 420 | /* |
| 421 | rez %= right_side_val; | 421 | * bash 4.2.45 x86 64bit: SEGV on 'echo $((2**63 / -1))' |
| 422 | * | ||
| 423 | * MAX_NEGATIVE_INT / -1 = MAX_POSITIVE_INT+1 | ||
| 424 | * and thus is not representable. | ||
| 425 | * Some CPUs segfault trying such op. | ||
| 426 | * Others overfolw MAX_POSITIVE_INT+1 to | ||
| 427 | * MAX_NEGATIVE_INT (0x7fff+1 = 0x8000). | ||
| 428 | * Make sure to at least not SEGV here: | ||
| 429 | */ | ||
| 430 | if (right_side_val == -1 | ||
| 431 | && rez << 1 == 0 /* MAX_NEGATIVE_INT or 0 */ | ||
| 432 | ) { | ||
| 433 | right_side_val = 1; | ||
| 434 | } | ||
| 435 | if (op == TOK_DIV || op == TOK_DIV_ASSIGN) | ||
| 436 | rez /= right_side_val; | ||
| 437 | else { | ||
| 438 | rez %= right_side_val; | ||
| 439 | } | ||
| 440 | } | ||
| 422 | } | 441 | } |
| 423 | 442 | ||
| 424 | if (is_assign_op(op)) { | 443 | if (is_assign_op(op)) { |
