mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-17 05:46:43 +00:00
169 lines
7.3 KiB
C
169 lines
7.3 KiB
C
// 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}}
|
|
}
|