|  | // 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; | 
|  | } |