ash,hush: do not segfault on $((2**63 / -1))
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
		
							
								
								
									
										27
									
								
								shell/math.c
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								shell/math.c
									
									
									
									
									
								
							@@ -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)
 | 
			
		||||
			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)) {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user