
Specifically, usernames containing `handle`, such as `chandlerc`, often end up in paths, including the path of this test file which contains the word `overflow`. Combined, they create a match for `handle.*overflow` in the filename on my system (but likely not many others), leading this test to mysteriously fail for unfortunate usernames like mine. =D No discussion of the amount of time I spent debugging this please. =[
188 lines
5.5 KiB
C
188 lines
5.5 KiB
C
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-undefined-ignore-overflow-pattern=all %s -emit-llvm -o - | FileCheck %s
|
|
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-undefined-ignore-overflow-pattern=all -fwrapv %s -emit-llvm -o - | FileCheck %s
|
|
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-undefined-ignore-overflow-pattern=add-signed-overflow-test,add-unsigned-overflow-test %s -emit-llvm -o - | FileCheck %s --check-prefix=ADD
|
|
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-undefined-ignore-overflow-pattern=negated-unsigned-const %s -emit-llvm -o - | FileCheck %s --check-prefix=NEGATE
|
|
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-undefined-ignore-overflow-pattern=unsigned-post-decr-while %s -emit-llvm -o - | FileCheck %s --check-prefix=WHILE
|
|
|
|
// Ensure some common overflow-dependent or overflow-prone code patterns don't
|
|
// trigger the overflow sanitizers. In many cases, overflow warnings caused by
|
|
// these patterns are seen as "noise" and result in users turning off
|
|
// sanitization all together.
|
|
|
|
// A pattern like "if (a + b < a)" simply checks for overflow and usually means
|
|
// the user is trying to handle it gracefully.
|
|
|
|
// Similarly, a pattern resembling "while (i--)" is extremely common and
|
|
// warning on its inevitable overflow can be seen as superfluous. Do note that
|
|
// using "i" in future calculations can be tricky because it will still
|
|
// wrap-around.
|
|
|
|
// Another common pattern that, in some cases, is found to be too noisy is
|
|
// unsigned negation, for example:
|
|
// unsigned long A = -1UL;
|
|
|
|
// Skip over parts of the IR containing this file's name.
|
|
// CHECK: source_filename = {{.*}}
|
|
|
|
// Ensure we don't see anything about handling overflow before the tests below.
|
|
// CHECK-NOT: handle{{.*}}overflow
|
|
|
|
extern unsigned a, b, c;
|
|
extern int u, v;
|
|
extern unsigned some(void);
|
|
|
|
// ADD-LABEL: @basic_commutativity
|
|
// WHILE-LABEL: @basic_commutativity
|
|
// NEGATE-LABEL: @basic_commutativity
|
|
// WHILE: handler.add_overflow
|
|
// NEGATE: handler.add_overflow
|
|
// ADD-NOT: handler.add_overflow
|
|
void basic_commutativity(void) {
|
|
if (a + b < a)
|
|
c = 9;
|
|
if (a + b < b)
|
|
c = 9;
|
|
if (b + a < b)
|
|
c = 9;
|
|
if (b + a < a)
|
|
c = 9;
|
|
if (a > a + b)
|
|
c = 9;
|
|
if (a > b + a)
|
|
c = 9;
|
|
if (b > a + b)
|
|
c = 9;
|
|
if (b > b + a)
|
|
c = 9;
|
|
if (u + v < u)
|
|
c = 9;
|
|
}
|
|
|
|
// ADD-LABEL: @arguments_and_commutativity
|
|
// WHILE-LABEL: @arguments_and_commutativity
|
|
// NEGATE-LABEL: @arguments_and_commutativity
|
|
// WHILE: handler.add_overflow
|
|
// NEGATE: handler.add_overflow
|
|
// ADD-NOT: handler.add_overflow
|
|
void arguments_and_commutativity(unsigned V1, unsigned V2) {
|
|
if (V1 + V2 < V1)
|
|
c = 9;
|
|
if (V1 + V2 < V2)
|
|
c = 9;
|
|
if (V2 + V1 < V2)
|
|
c = 9;
|
|
if (V2 + V1 < V1)
|
|
c = 9;
|
|
if (V1 > V1 + V2)
|
|
c = 9;
|
|
if (V1 > V2 + V1)
|
|
c = 9;
|
|
if (V2 > V1 + V2)
|
|
c = 9;
|
|
if (V2 > V2 + V1)
|
|
c = 9;
|
|
}
|
|
|
|
// ADD-LABEL: @pointers
|
|
// WHILE-LABEL: @pointers
|
|
// NEGATE-LABEL: @pointers
|
|
// WHILE: handler.add_overflow
|
|
// NEGATE: handler.add_overflow
|
|
// ADD-NOT: handler.add_overflow
|
|
void pointers(unsigned *P1, unsigned *P2, unsigned V1) {
|
|
if (*P1 + *P2 < *P1)
|
|
c = 9;
|
|
if (*P1 + V1 < V1)
|
|
c = 9;
|
|
if (V1 + *P2 < *P2)
|
|
c = 9;
|
|
}
|
|
|
|
struct OtherStruct {
|
|
unsigned foo, bar;
|
|
};
|
|
|
|
struct MyStruct {
|
|
unsigned base, offset;
|
|
struct OtherStruct os;
|
|
};
|
|
|
|
extern struct MyStruct ms;
|
|
|
|
// ADD-LABEL: @structs
|
|
// WHILE-LABEL: @structs
|
|
// NEGATE-LABEL: @structs
|
|
// WHILE: handler.add_overflow
|
|
// NEGATE: handler.add_overflow
|
|
// ADD-NOT: handler.add_overflow
|
|
void structs(void) {
|
|
if (ms.base + ms.offset < ms.base)
|
|
c = 9;
|
|
}
|
|
|
|
// ADD-LABEL: @nestedstructs
|
|
// WHILE-LABEL: @nestedstructs
|
|
// NEGATE-LABEL: @nestedstructs
|
|
// WHILE: handler.add_overflow
|
|
// NEGATE: handler.add_overflow
|
|
// ADD-NOT: handler.add_overflow
|
|
void nestedstructs(void) {
|
|
if (ms.os.foo + ms.os.bar < ms.os.foo)
|
|
c = 9;
|
|
}
|
|
|
|
// ADD-LABEL: @constants
|
|
// WHILE-LABEL: @constants
|
|
// NEGATE-LABEL: @constants
|
|
// WHILE: handler.add_overflow
|
|
// NEGATE: handler.add_overflow
|
|
// ADD-NOT: handler.add_overflow
|
|
// Normally, this would be folded into a simple call to the overflow handler
|
|
// and a store. Excluding this pattern results in just a store.
|
|
void constants(void) {
|
|
unsigned base = 4294967295;
|
|
unsigned offset = 1;
|
|
if (base + offset < base)
|
|
c = 9;
|
|
}
|
|
// ADD-LABEL: @common_while
|
|
// NEGATE-LABEL: @common_while
|
|
// WHILE-LABEL: @common_while
|
|
// ADD: usub.with.overflow
|
|
// NEGATE: usub.with.overflow
|
|
// WHILE: %dec = add i32 %0, -1
|
|
void common_while(unsigned i) {
|
|
// This post-decrement usually causes overflow sanitizers to trip on the very
|
|
// last operation.
|
|
while (i--) {
|
|
some();
|
|
}
|
|
}
|
|
|
|
// ADD-LABEL: @negation
|
|
// NEGATE-LABEL: @negation
|
|
// WHILE-LABEL @negation
|
|
// ADD: negate_overflow
|
|
// NEGATE-NOT: negate_overflow
|
|
// WHILE: negate_overflow
|
|
// Normally, these assignments would trip the unsigned overflow sanitizer.
|
|
void negation(void) {
|
|
#define SOME -1UL
|
|
unsigned long A = -1UL;
|
|
unsigned long B = -2UL;
|
|
unsigned long C = -SOME;
|
|
(void)A;(void)B;(void)C;
|
|
}
|
|
|
|
|
|
// ADD-LABEL: @function_call
|
|
// WHILE-LABEL: @function_call
|
|
// NEGATE-LABEL: @function_call
|
|
// WHILE: handler.add_overflow
|
|
// NEGATE: handler.add_overflow
|
|
// ADD-NOT: handler.add_overflow
|
|
void function_call(void) {
|
|
if (b + some() < b)
|
|
c = 9;
|
|
}
|