188 lines · c
1// 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 %s2// 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 %s3// 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=ADD4// 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=NEGATE5// 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=WHILE6 7// Ensure some common overflow-dependent or overflow-prone code patterns don't8// trigger the overflow sanitizers. In many cases, overflow warnings caused by9// these patterns are seen as "noise" and result in users turning off10// sanitization all together.11 12// A pattern like "if (a + b < a)" simply checks for overflow and usually means13// the user is trying to handle it gracefully.14 15// Similarly, a pattern resembling "while (i--)" is extremely common and16// warning on its inevitable overflow can be seen as superfluous. Do note that17// using "i" in future calculations can be tricky because it will still18// wrap-around.19 20// Another common pattern that, in some cases, is found to be too noisy is21// unsigned negation, for example:22// unsigned long A = -1UL;23 24// Skip over parts of the IR containing this file's name.25// CHECK: source_filename = {{.*}}26 27// Ensure we don't see anything about handling overflow before the tests below.28// CHECK-NOT: handle{{.*}}overflow29 30extern unsigned a, b, c;31extern int u, v;32extern unsigned some(void);33 34// ADD-LABEL: @basic_commutativity35// WHILE-LABEL: @basic_commutativity36// NEGATE-LABEL: @basic_commutativity37// WHILE: handler.add_overflow38// NEGATE: handler.add_overflow39// ADD-NOT: handler.add_overflow40void basic_commutativity(void) {41 if (a + b < a)42 c = 9;43 if (a + b < b)44 c = 9;45 if (b + a < b)46 c = 9;47 if (b + a < a)48 c = 9;49 if (a > a + b)50 c = 9;51 if (a > b + a)52 c = 9;53 if (b > a + b)54 c = 9;55 if (b > b + a)56 c = 9;57 if (u + v < u)58 c = 9;59}60 61// ADD-LABEL: @arguments_and_commutativity62// WHILE-LABEL: @arguments_and_commutativity63// NEGATE-LABEL: @arguments_and_commutativity64// WHILE: handler.add_overflow65// NEGATE: handler.add_overflow66// ADD-NOT: handler.add_overflow67void arguments_and_commutativity(unsigned V1, unsigned V2) {68 if (V1 + V2 < V1)69 c = 9;70 if (V1 + V2 < V2)71 c = 9;72 if (V2 + V1 < V2)73 c = 9;74 if (V2 + V1 < V1)75 c = 9;76 if (V1 > V1 + V2)77 c = 9;78 if (V1 > V2 + V1)79 c = 9;80 if (V2 > V1 + V2)81 c = 9;82 if (V2 > V2 + V1)83 c = 9;84}85 86// ADD-LABEL: @pointers87// WHILE-LABEL: @pointers88// NEGATE-LABEL: @pointers89// WHILE: handler.add_overflow90// NEGATE: handler.add_overflow91// ADD-NOT: handler.add_overflow92void pointers(unsigned *P1, unsigned *P2, unsigned V1) {93 if (*P1 + *P2 < *P1)94 c = 9;95 if (*P1 + V1 < V1)96 c = 9;97 if (V1 + *P2 < *P2)98 c = 9;99}100 101struct OtherStruct {102 unsigned foo, bar;103};104 105struct MyStruct {106 unsigned base, offset;107 struct OtherStruct os;108};109 110extern struct MyStruct ms;111 112// ADD-LABEL: @structs113// WHILE-LABEL: @structs114// NEGATE-LABEL: @structs115// WHILE: handler.add_overflow116// NEGATE: handler.add_overflow117// ADD-NOT: handler.add_overflow118void structs(void) {119 if (ms.base + ms.offset < ms.base)120 c = 9;121}122 123// ADD-LABEL: @nestedstructs124// WHILE-LABEL: @nestedstructs125// NEGATE-LABEL: @nestedstructs126// WHILE: handler.add_overflow127// NEGATE: handler.add_overflow128// ADD-NOT: handler.add_overflow129void nestedstructs(void) {130 if (ms.os.foo + ms.os.bar < ms.os.foo)131 c = 9;132}133 134// ADD-LABEL: @constants135// WHILE-LABEL: @constants136// NEGATE-LABEL: @constants137// WHILE: handler.add_overflow138// NEGATE: handler.add_overflow139// ADD-NOT: handler.add_overflow140// Normally, this would be folded into a simple call to the overflow handler141// and a store. Excluding this pattern results in just a store.142void constants(void) {143 unsigned base = 4294967295;144 unsigned offset = 1;145 if (base + offset < base)146 c = 9;147}148// ADD-LABEL: @common_while149// NEGATE-LABEL: @common_while150// WHILE-LABEL: @common_while151// ADD: usub.with.overflow152// NEGATE: usub.with.overflow153// WHILE: %dec = add i32 %0, -1154void common_while(unsigned i) {155 // This post-decrement usually causes overflow sanitizers to trip on the very156 // last operation.157 while (i--) {158 some();159 }160}161 162// ADD-LABEL: @negation163// NEGATE-LABEL: @negation164// WHILE-LABEL @negation165// ADD: negate_overflow166// NEGATE-NOT: negate_overflow167// WHILE: negate_overflow168// Normally, these assignments would trip the unsigned overflow sanitizer.169void negation(void) {170#define SOME -1UL171 unsigned long A = -1UL;172 unsigned long B = -2UL;173 unsigned long C = -SOME;174 (void)A;(void)B;(void)C;175}176 177 178// ADD-LABEL: @function_call179// WHILE-LABEL: @function_call180// NEGATE-LABEL: @function_call181// WHILE: handler.add_overflow182// NEGATE: handler.add_overflow183// ADD-NOT: handler.add_overflow184void function_call(void) {185 if (b + some() < b)186 c = 9;187}188