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

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
diff --git a/shell/math.c b/shell/math.c
index 3da1511..e7565eb 100644
--- a/shell/math.c
+++ b/shell/math.c
@@ -415,10 +415,29 @@
 		}
 		else if (right_side_val == 0)
 			return "divide by zero";
-		else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
-			rez /= right_side_val;
-		else if (op == TOK_REM || op == TOK_REM_ASSIGN)
-			rez %= right_side_val;
+		else if (op == TOK_DIV || op == TOK_DIV_ASSIGN
+		      || op == TOK_REM || op == TOK_REM_ASSIGN) {
+			/*
+			 * 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)) {