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 %s 2 // 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 3 // 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 4 // 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 5 // 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 6 7 // Ensure some common overflow-dependent or overflow-prone code patterns don't 8 // trigger the overflow sanitizers. In many cases, overflow warnings caused by 9 // these patterns are seen as "noise" and result in users turning off 10 // sanitization all together. 11 12 // A pattern like "if (a + b < a)" simply checks for overflow and usually means 13 // the user is trying to handle it gracefully. 14 15 // Similarly, a pattern resembling "while (i--)" is extremely common and 16 // warning on its inevitable overflow can be seen as superfluous. Do note that 17 // using "i" in future calculations can be tricky because it will still 18 // wrap-around. 19 20 // Another common pattern that, in some cases, is found to be too noisy is 21 // 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{{.*}}overflow 29 30 extern unsigned a, b, c; 31 extern int u, v; 32 extern unsigned some(void); 33 34 // ADD-LABEL: @basic_commutativity 35 // WHILE-LABEL: @basic_commutativity 36 // NEGATE-LABEL: @basic_commutativity 37 // WHILE: handler.add_overflow 38 // NEGATE: handler.add_overflow 39 // ADD-NOT: handler.add_overflow 40 void 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_commutativity 62 // WHILE-LABEL: @arguments_and_commutativity 63 // NEGATE-LABEL: @arguments_and_commutativity 64 // WHILE: handler.add_overflow 65 // NEGATE: handler.add_overflow 66 // ADD-NOT: handler.add_overflow 67 void 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: @pointers 87 // WHILE-LABEL: @pointers 88 // NEGATE-LABEL: @pointers 89 // WHILE: handler.add_overflow 90 // NEGATE: handler.add_overflow 91 // ADD-NOT: handler.add_overflow 92 void 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 101 struct OtherStruct { 102 unsigned foo, bar; 103 }; 104 105 struct MyStruct { 106 unsigned base, offset; 107 struct OtherStruct os; 108 }; 109 110 extern struct MyStruct ms; 111 112 // ADD-LABEL: @structs 113 // WHILE-LABEL: @structs 114 // NEGATE-LABEL: @structs 115 // WHILE: handler.add_overflow 116 // NEGATE: handler.add_overflow 117 // ADD-NOT: handler.add_overflow 118 void structs(void) { 119 if (ms.base + ms.offset < ms.base) 120 c = 9; 121 } 122 123 // ADD-LABEL: @nestedstructs 124 // WHILE-LABEL: @nestedstructs 125 // NEGATE-LABEL: @nestedstructs 126 // WHILE: handler.add_overflow 127 // NEGATE: handler.add_overflow 128 // ADD-NOT: handler.add_overflow 129 void nestedstructs(void) { 130 if (ms.os.foo + ms.os.bar < ms.os.foo) 131 c = 9; 132 } 133 134 // ADD-LABEL: @constants 135 // WHILE-LABEL: @constants 136 // NEGATE-LABEL: @constants 137 // WHILE: handler.add_overflow 138 // NEGATE: handler.add_overflow 139 // ADD-NOT: handler.add_overflow 140 // Normally, this would be folded into a simple call to the overflow handler 141 // and a store. Excluding this pattern results in just a store. 142 void constants(void) { 143 unsigned base = 4294967295; 144 unsigned offset = 1; 145 if (base + offset < base) 146 c = 9; 147 } 148 // ADD-LABEL: @common_while 149 // NEGATE-LABEL: @common_while 150 // WHILE-LABEL: @common_while 151 // ADD: usub.with.overflow 152 // NEGATE: usub.with.overflow 153 // WHILE: %dec = add i32 %0, -1 154 void common_while(unsigned i) { 155 // This post-decrement usually causes overflow sanitizers to trip on the very 156 // last operation. 157 while (i--) { 158 some(); 159 } 160 } 161 162 // ADD-LABEL: @negation 163 // NEGATE-LABEL: @negation 164 // WHILE-LABEL @negation 165 // ADD: negate_overflow 166 // NEGATE-NOT: negate_overflow 167 // WHILE: negate_overflow 168 // Normally, these assignments would trip the unsigned overflow sanitizer. 169 void negation(void) { 170 #define SOME -1UL 171 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_call 179 // WHILE-LABEL: @function_call 180 // NEGATE-LABEL: @function_call 181 // WHILE: handler.add_overflow 182 // NEGATE: handler.add_overflow 183 // ADD-NOT: handler.add_overflow 184 void function_call(void) { 185 if (b + some() < b) 186 c = 9; 187 } 188