xref: /llvm-project/clang/test/CodeGen/ignore-overflow-pattern.c (revision 1e5c1a342e87961513da84a55cb7a3c3ba22b354)
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