ash,hush: do not segfault on $((2**63 / -1))

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2014-11-18 14:32:58 +01:00
parent 08a5dab181
commit 8a475def9e

View File

@ -415,10 +415,29 @@ arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_
} }
else if (right_side_val == 0) else if (right_side_val == 0)
return "divide by zero"; return "divide by zero";
else if (op == TOK_DIV || op == TOK_DIV_ASSIGN) else if (op == TOK_DIV || op == TOK_DIV_ASSIGN
rez /= right_side_val; || op == TOK_REM || op == TOK_REM_ASSIGN) {
else if (op == TOK_REM || op == TOK_REM_ASSIGN) /*
rez %= right_side_val; * bash 4.2.45 x86 64bit: SEGV on 'echo $((2**63 / -1))'
*
* MAX_NEGATIVE_INT / -1 = MAX_POSITIVE_INT+1
* and thus is not representable.
* Some CPUs segfault trying such op.
* Others overfolw MAX_POSITIVE_INT+1 to
* MAX_NEGATIVE_INT (0x7fff+1 = 0x8000).
* Make sure to at least not SEGV here:
*/
if (right_side_val == -1
&& rez << 1 == 0 /* MAX_NEGATIVE_INT or 0 */
) {
right_side_val = 1;
}
if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
rez /= right_side_val;
else {
rez %= right_side_val;
}
}
} }
if (is_assign_op(op)) { if (is_assign_op(op)) {