blob: 5f37d9976263ae501a28dcea706adfb9d571ab01 [file] [log] [blame]
// RUN: %clang_analyze_cc1 -analyzer-checker=core.BitwiseShift \
// RUN: -analyzer-checker=debug.ExprInspection \
// RUN: -analyzer-output=text -verify \
// RUN: -triple x86_64-pc-linux-gnu -x c %s \
// RUN: -Wno-shift-count-negative -Wno-shift-negative-value \
// RUN: -Wno-shift-count-overflow -Wno-shift-overflow \
// RUN: -Wno-shift-sign-overflow
//
// RUN: %clang_analyze_cc1 -analyzer-checker=core.BitwiseShift \
// RUN: -analyzer-checker=debug.ExprInspection \
// RUN: -analyzer-config core.BitwiseShift:Pedantic=true \
// RUN: -analyzer-output=text -verify \
// RUN: -triple x86_64-pc-linux-gnu -x c++ -std=c++20 %s \
// RUN: -Wno-shift-count-negative -Wno-shift-negative-value \
// RUN: -Wno-shift-count-overflow -Wno-shift-overflow \
// RUN: -Wno-shift-sign-overflow
//
// This test file verifies the default behavior of the BitwiseShift checker,
// which reports the serious logical defects, but doesn't warn on code that's
// legal under C++20 (or later) and widely accepted (but theoretically
// undefined) in other compilation modes.
// TEST NEGATIVE RIGHT OPERAND
//===----------------------------------------------------------------------===//
int negative_right_operand_literal(void) {
return 2 << -2;
// expected-warning@-1 {{Right operand is negative in left shift}}
// expected-note@-2 {{The result of left shift is undefined because the right operand is negative}}
}
int negative_right_operand_symbolic(int left, int right) {
// expected-note@+2 {{Assuming 'right' is < 0}}
// expected-note@+1 {{Taking false branch}}
if (right >= 0)
return 0;
return left >> right;
// expected-warning@-1 {{Right operand is negative in right shift}}
// expected-note@-2 {{The result of right shift is undefined because the right operand is negative}}
}
int negative_right_operand_compound(short arg) {
// expected-note@+2 {{Assuming 'arg' is < 2}}
// expected-note@+1 {{Taking false branch}}
if (arg >= 2 )
return 0;
return 2 << (arg - 1 - 1 - 1);
// expected-warning@-1 {{Right operand is negative in left shift}}
// expected-note@-2 {{The result of left shift is undefined because the right operand is negative}}
}
// TEST TOO LARGE RIGHT OPERAND
//===----------------------------------------------------------------------===//
int too_large_right_operand_literal(void) {
return 2 << 32;
// expected-warning@-1 {{Left shift by '32' overflows the capacity of 'int'}}
// expected-note@-2 {{The result of left shift is undefined because the right operand '32' is not smaller than 32, the capacity of 'int'}}
}
int too_large_right_operand_exact_symbolic(int arg) {
// expected-note@+4 {{Assuming 'arg' is > 33}}
// expected-note@+3 {{Left side of '||' is false}}
// expected-note@+2 {{Assuming 'arg' is < 35}}
// expected-note@+1 {{Taking false branch}}
if (arg <= 33 || arg >= 35)
return 0;
return 3 << arg;
// expected-warning@-1 {{Left shift by '34' overflows the capacity of 'int'}}
// expected-note@-2 {{The result of left shift is undefined because the right operand '34' is not smaller than 32, the capacity of 'int'}}
}
int too_large_right_operand_exact_symbolic_2(char arg) {
// expected-note@+2 {{Assuming the condition is false}}
// expected-note@+1 {{Taking false branch}}
if (arg != ' ')
return 0;
return 3 << arg;
// expected-warning@-1 {{Left shift by '32' overflows the capacity of 'int'}}
// expected-note@-2 {{The result of left shift is undefined because the right operand '32' is not smaller than 32, the capacity of 'int'}}
}
int too_large_right_operand_symbolic(int left, int right) {
// expected-note@+2 {{Assuming 'right' is > 31}}
// expected-note@+1 {{Taking false branch}}
if (right <= 31)
return 0;
return left >> right;
// expected-warning@-1 {{Right shift overflows the capacity of 'int'}}
// expected-note@-2 {{The result of right shift is undefined because the right operand is >= 32, not smaller than 32, the capacity of 'int'}}
}
void clang_analyzer_value(int);
int too_large_right_operand_compound(unsigned short arg) {
// Note: this would be valid code with an 'unsigned int' because
// unsigned addition is allowed to overflow.
clang_analyzer_value(32+arg);
// expected-warning@-1 {{32s:{ [-2147483648, 2147483647] }}
// expected-note@-2 {{32s:{ [-2147483648, 2147483647] }}
return 1 << (32 + arg);
// expected-warning@-1 {{Left shift overflows the capacity of 'int'}}
// expected-note@-2 {{The result of left shift is undefined because the right operand is not smaller than 32, the capacity of 'int'}}
// FIXME: this message should be
// {{The result of left shift is undefined because the right operand is >= 32, not smaller than 32, the capacity of 'int'}}
// but for some reason neither the new logic, nor debug.ExprInspection and
// clang_analyzer_value reports this range information.
}
// TEST STATE UPDATES
//===----------------------------------------------------------------------===//
void state_update(char a, int *p) {
// NOTE: with 'int a' this would not produce a bug report because the engine
// would not rule out an overflow.
*p += 1 << a;
// expected-note@-1 {{Assuming right operand of bit shift is non-negative but less than 32}}
*p += 1 << (a + 32);
// expected-warning@-1 {{Left shift overflows the capacity of 'int'}}
// expected-note@-2 {{The result of left shift is undefined because the right operand is not smaller than 32, the capacity of 'int'}}
}
void state_update_2(char a, int *p) {
*p += 1234 >> (a + 32);
// expected-note@-1 {{Assuming right operand of bit shift is non-negative but less than 32}}
*p += 1234 >> a;
// expected-warning@-1 {{Right operand is negative in right shift}}
// expected-note@-2 {{The result of right shift is undefined because the right operand is negative}}
}
// TEST EXPRESSION TRACKING
//===----------------------------------------------------------------------===//
// Expression tracking a "generic" tool that's used by many other checkers,
// so this is just a minimal test to see that it's activated.
void setValue(unsigned *p, unsigned newval) {
*p = newval;
// expected-note@-1 {{The value 33 is assigned to 'right'}}
}
int expression_tracked_back(void) {
unsigned left = 115; // expected-note {{'left' initialized to 115}}
unsigned right;
setValue(&right, 33);
// expected-note@-1 {{Calling 'setValue'}}
// expected-note@-2 {{Passing the value 33 via 2nd parameter 'newval'}}
// expected-note@-3 {{Returning from 'setValue'}}
return left << right;
// expected-warning@-1 {{Left shift by '33' overflows the capacity of 'unsigned int'}}
// expected-note@-2 {{The result of left shift is undefined because the right operand '33' is not smaller than 32, the capacity of 'unsigned int'}}
}
// TEST PERMISSIVENESS
//===----------------------------------------------------------------------===//
int allow_overflows_and_negative_operands(void) {
// These are all legal under C++20 and many compilers accept them under
// earlier standards as well.
int int_min = 1 << 31; // no-warning
int this_overflows = 1027 << 30; // no-warning
return (-2 << 5) + (-3 >> 4); // no-warning
}
int double_negative(void) {
return -2 >> -2;
// expected-warning@-1 {{Right operand is negative in right shift}}
// expected-note@-2 {{The result of right shift is undefined because the right operand is negative}}
}