xref: /llvm-project/clang/test/Analysis/call-invalidation.cpp (revision 90929dd97a8f2c00148bee676bf8b44bec063d9b)
1 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify -analyzer-config eagerly-assume=false %s
2 
3 template <class T> void clang_analyzer_dump(T);
4 void clang_analyzer_eval(bool);
5 
6 void usePointer(int * const *);
7 void useReference(int * const &);
8 
9 void testPointer() {
10   int x;
11   int *p;
12 
13   p = &x;
14   x = 42;
15   clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
16   usePointer(&p);
17   clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}}
18 
19   p = &x;
20   x = 42;
21   clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
22   useReference(p);
23   clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}}
24 
25   int * const cp1 = &x;
26   x = 42;
27   clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
28   usePointer(&cp1);
29   clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}}
30 
31   int * const cp2 = &x;
32   x = 42;
33   clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
34   useReference(cp2);
35   clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}}
36 }
37 
38 
39 struct Wrapper {
40   int *ptr;
41 };
42 
43 void useStruct(Wrapper &w);
44 void useConstStruct(const Wrapper &w);
45 
46 void testPointerStruct() {
47   int x;
48   Wrapper w;
49 
50   w.ptr = &x;
51   x = 42;
52   clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
53   useStruct(w);
54   clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}}
55 
56   w.ptr = &x;
57   x = 42;
58   clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
59   useConstStruct(w);
60   clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}}
61 }
62 
63 
64 struct RefWrapper {
65   int &ref;
66 };
67 
68 void useStruct(RefWrapper &w);
69 void useConstStruct(const RefWrapper &w);
70 
71 void testReferenceStruct() {
72   int x;
73   RefWrapper w = { x };
74 
75   x = 42;
76   clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
77   useStruct(w);
78   clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}}
79 }
80 
81 // FIXME: This test is split into two functions because region invalidation
82 // does not preserve reference bindings.
83 void testConstReferenceStruct() {
84   int x;
85   RefWrapper w = { x };
86 
87   x = 42;
88   clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
89   useConstStruct(w);
90   clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}}
91 }
92 
93 
94 int usePointerPure(int * const *) __attribute__((pure));
95 int usePointerConst(int * const *) __attribute__((const));
96 
97 void testPureConst() {
98   extern int global;
99   int x;
100   int *p;
101 
102   p = &x;
103   x = 42;
104   global = -5;
105   clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
106   clang_analyzer_eval(global == -5); // expected-warning{{TRUE}}
107 
108   (void)usePointerPure(&p);
109   clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
110   clang_analyzer_eval(global == -5); // expected-warning{{TRUE}}
111 
112   (void)usePointerConst(&p);
113   clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
114   clang_analyzer_eval(global == -5); // expected-warning{{TRUE}}
115 
116   usePointer(&p);
117   clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}}
118   clang_analyzer_eval(global == -5); // expected-warning{{UNKNOWN}}
119 }
120 
121 
122 struct PlainStruct {
123   int x, y;
124   mutable int z;
125 };
126 
127 PlainStruct glob;
128 
129 void useAnything(void *);
130 void useAnythingConst(const void *);
131 
132 void testInvalidationThroughBaseRegionPointer() {
133   PlainStruct s1;
134   s1.x = 1;
135   s1.z = 1;
136   clang_analyzer_eval(s1.x == 1); // expected-warning{{TRUE}}
137   clang_analyzer_eval(s1.z == 1); // expected-warning{{TRUE}}
138   // Not only passing a structure pointer through const pointer parameter,
139   // but also passing a field pointer through const pointer parameter
140   // should preserve the contents of the structure.
141   useAnythingConst(&(s1.y));
142   clang_analyzer_eval(s1.x == 1); // expected-warning{{TRUE}}
143   // FIXME: Should say "UNKNOWN", because it is not uncommon to
144   // modify a mutable member variable through const pointer.
145   clang_analyzer_eval(s1.z == 1); // expected-warning{{TRUE}}
146   useAnything(&(s1.y));
147   clang_analyzer_eval(s1.x == 1); // expected-warning{{UNKNOWN}}
148 }
149 
150 
151 void useFirstConstSecondNonConst(const void *x, void *y);
152 void useFirstNonConstSecondConst(void *x, const void *y);
153 
154 void testMixedConstNonConstCalls() {
155   PlainStruct s2;
156   s2.x = 1;
157   useFirstConstSecondNonConst(&(s2.x), &(s2.y));
158   clang_analyzer_eval(s2.x == 1); // expected-warning{{UNKNOWN}}
159   s2.x = 1;
160   useFirstNonConstSecondConst(&(s2.x), &(s2.y));
161   clang_analyzer_eval(s2.x == 1); // expected-warning{{UNKNOWN}}
162   s2.y = 1;
163   useFirstConstSecondNonConst(&(s2.x), &(s2.y));
164   clang_analyzer_eval(s2.y == 1); // expected-warning{{UNKNOWN}}
165   s2.y = 1;
166   useFirstNonConstSecondConst(&(s2.x), &(s2.y));
167   clang_analyzer_eval(s2.y == 1); // expected-warning{{UNKNOWN}}
168 }
169 
170 namespace std {
171 class Opaque {
172 public:
173   Opaque();
174   int nested_member;
175 };
176 } // namespace std
177 
178 struct StdWrappingOpaque {
179   std::Opaque o; // first member
180   int uninit;
181 };
182 struct StdWrappingOpaqueSwapped {
183   int uninit; // first member
184   std::Opaque o;
185 };
186 
187 int testStdCtorDoesNotInvalidateParentObject() {
188   StdWrappingOpaque obj;
189   int x = obj.o.nested_member; // no-garbage: std::Opaque::ctor might initialized this
190   int y = obj.uninit; // FIXME: We should have a garbage read here. Read the details.
191   // As the first member ("obj.o") is invalidated, a conjured default binding is bound
192   // to the offset 0 within cluster "obj", and this masks every uninitialized fields
193   // that follows. We need a better store with extents to fix this.
194   return x + y;
195 }
196 
197 int testStdCtorDoesNotInvalidateParentObjectSwapped() {
198   StdWrappingOpaqueSwapped obj;
199   int x = obj.o.nested_member; // no-garbage: std::Opaque::ctor might initialized this
200   int y = obj.uninit; // expected-warning {{Assigned value is garbage or undefined}}
201   return x + y;
202 }
203 
204 class UserProvidedOpaque {
205 public:
206   UserProvidedOpaque(); // might reinterpret_cast(this)
207   int nested_member;
208 };
209 
210 struct WrappingUserProvidedOpaque {
211   UserProvidedOpaque o; // first member
212   int uninit;
213 };
214 struct WrappingUserProvidedOpaqueSwapped {
215   int uninit; // first member
216   UserProvidedOpaque o;
217 };
218 
219 int testUserProvidedCtorInvalidatesParentObject() {
220   WrappingUserProvidedOpaque obj;
221   int x = obj.o.nested_member; // no-garbage: UserProvidedOpaque::ctor might initialized this
222   int y = obj.uninit; // no-garbage: UserProvidedOpaque::ctor might reinterpret_cast(this) and write to the "uninit" member.
223   return x + y;
224 }
225 
226 int testUserProvidedCtorInvalidatesParentObjectSwapped() {
227   WrappingUserProvidedOpaqueSwapped obj;
228   int x = obj.o.nested_member; // no-garbage: same as above
229   int y = obj.uninit; // no-garbage: same as above
230   return x + y;
231 }
232 
233 struct WrappingStdWrappingOpaqueOuterInits {
234   int first = 1;
235   std::Opaque second;
236   int third = 3;
237   WrappingStdWrappingOpaqueOuterInits() {
238     clang_analyzer_dump(first); // expected-warning {{1 S32b}}
239     clang_analyzer_dump(second.nested_member); // expected-warning {{derived_}}
240     clang_analyzer_dump(third); // expected-warning {{3 S32b}}
241   }
242 };
243 
244 struct WrappingUserProvidedOpaqueOuterInits {
245   int first = 1; // Potentially overwritten by UserProvidedOpaque::ctor
246   UserProvidedOpaque second; // Invalidates the object so far.
247   int third = 3; // Happens after UserProvidedOpaque::ctor, thus preserved!
248   WrappingUserProvidedOpaqueOuterInits() {
249     clang_analyzer_dump(first); // expected-warning {{derived_}}
250     clang_analyzer_dump(second.nested_member); // expected-warning {{derived_}}
251     clang_analyzer_dump(third); // expected-warning {{3 S32b}}
252   }
253 };
254 
255 extern "C++" {
256 namespace std {
257 inline namespace v1 {
258 namespace custom_ranges {
259 struct Fancy {
260 struct iterator {
261 struct Opaque {
262   Opaque();
263   int nested_member;
264 }; // struct Opaque
265 }; // struct iterator
266 }; // struct Fancy
267 } // namespace custom_ranges
268 } // namespace v1
269 } // namespace std
270 } // extern "C++"
271 
272 struct StdWrappingFancyOpaque {
273   int uninit;
274   std::custom_ranges::Fancy::iterator::Opaque o;
275 };
276 
277 int testNestedStdNamespacesAndRecords() {
278   StdWrappingFancyOpaque obj;
279   int x = obj.o.nested_member; // no-garbage: ctor
280   int y = obj.uninit; // expected-warning {{Assigned value is garbage or undefined}}
281   return x + y;
282 }
283