1 | // RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=text -analyzer-config c++-inlining=destructors -std=c++11 -verify -Wno-tautological-undefined-compare %s |
2 | // RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config c++-inlining=destructors -std=c++11 %s -o %t.plist -Wno-tautological-undefined-compare |
3 | // RUN: cat %t.plist | %diff_plist %S/Inputs/expected-plists/path-notes.cpp.plist - |
4 | |
5 | class Foo { |
6 | public: |
7 | static void use(int *p) { |
8 | *p = 1; // expected-warning {{Dereference of null pointer (loaded from variable 'p')}} |
9 | // expected-note@-1 {{Dereference of null pointer (loaded from variable 'p')}} |
10 | } |
11 | |
12 | Foo(int *p) { |
13 | use(p); |
14 | // expected-note@-1 {{Passing null pointer value via 1st parameter 'p'}} |
15 | // expected-note@-2 {{Calling 'Foo::use'}} |
16 | } |
17 | }; |
18 | |
19 | static int *globalPtr; |
20 | |
21 | class Bar { |
22 | public: |
23 | ~Bar() { |
24 | Foo f(globalPtr); |
25 | // expected-note@-1 {{Passing null pointer value via 1st parameter 'p'}} |
26 | // expected-note@-2 {{Calling constructor for 'Foo'}} |
27 | } |
28 | }; |
29 | |
30 | void test() { |
31 | Bar b; |
32 | globalPtr = 0; |
33 | // expected-note@-1 {{Null pointer value stored to 'globalPtr'}} |
34 | } // expected-note {{Calling '~Bar'}} |
35 | |
36 | |
37 | void testAnonymous() { |
38 | class { |
39 | public: |
40 | void method(int *p) { |
41 | *p = 1; // expected-warning {{Dereference of null pointer (loaded from variable 'p')}} |
42 | // expected-note@-1 {{Dereference of null pointer (loaded from variable 'p')}} |
43 | } |
44 | } anonymous; |
45 | |
46 | anonymous.method(0); |
47 | // expected-note@-1 {{Passing null pointer value via 1st parameter 'p'}} |
48 | // expected-note@-2 {{Calling 'method'}} |
49 | } |
50 | |
51 | |
52 | // A simplified version of std::move. |
53 | template <typename T> |
54 | T &&move(T &obj) { |
55 | return static_cast<T &&>(obj); |
56 | } |
57 | |
58 | |
59 | namespace defaulted { |
60 | class Dereferencer { |
61 | public: |
62 | Dereferencer() { |
63 | *globalPtr = 1; // expected-warning {{Dereference of null pointer (loaded from variable 'globalPtr')}} |
64 | // expected-note@-1 {{Dereference of null pointer (loaded from variable 'globalPtr')}} |
65 | } |
66 | |
67 | Dereferencer(const Dereferencer &Other) { |
68 | *globalPtr = 1; // expected-warning {{Dereference of null pointer (loaded from variable 'globalPtr')}} |
69 | // expected-note@-1 {{Dereference of null pointer (loaded from variable 'globalPtr')}} |
70 | } |
71 | |
72 | Dereferencer(Dereferencer &&Other) { |
73 | *globalPtr = 1; // expected-warning {{Dereference of null pointer (loaded from variable 'globalPtr')}} |
74 | // expected-note@-1 {{Dereference of null pointer (loaded from variable 'globalPtr')}} |
75 | } |
76 | |
77 | void operator=(const Dereferencer &Other) { |
78 | *globalPtr = 1; // expected-warning {{Dereference of null pointer (loaded from variable 'globalPtr')}} |
79 | // expected-note@-1 {{Dereference of null pointer (loaded from variable 'globalPtr')}} |
80 | } |
81 | |
82 | void operator=(Dereferencer &&Other) { |
83 | *globalPtr = 1; // expected-warning {{Dereference of null pointer (loaded from variable 'globalPtr')}} |
84 | // expected-note@-1 {{Dereference of null pointer (loaded from variable 'globalPtr')}} |
85 | } |
86 | |
87 | ~Dereferencer() { |
88 | *globalPtr = 1; // expected-warning {{Dereference of null pointer (loaded from variable 'globalPtr')}} |
89 | // expected-note@-1 {{Dereference of null pointer (loaded from variable 'globalPtr')}} |
90 | } |
91 | }; |
92 | |
93 | class Wrapper { |
94 | Dereferencer d; |
95 | }; |
96 | |
97 | class MovableWrapper { |
98 | Dereferencer d; |
99 | public: |
100 | MovableWrapper() = default; |
101 | |
102 | MovableWrapper(MovableWrapper &&Other) = default; |
103 | // expected-note@-1 {{Calling move constructor for 'Dereferencer'}} |
104 | |
105 | MovableWrapper &operator=(MovableWrapper &&Other) = default; |
106 | // expected-note@-1 {{Calling move assignment operator for 'Dereferencer'}} |
107 | }; |
108 | |
109 | void testDefaultConstruction() { |
110 | globalPtr = 0; |
111 | // expected-note@-1 {{Null pointer value stored to 'globalPtr'}} |
112 | Wrapper w; |
113 | // expected-note@-1 {{Calling implicit default constructor for 'Wrapper'}} |
114 | // expected-note@-2 {{Calling default constructor for 'Dereferencer'}} |
115 | } |
116 | |
117 | void testCopyConstruction(const Wrapper &input) { |
118 | globalPtr = 0; |
119 | // expected-note@-1 {{Null pointer value stored to 'globalPtr'}} |
120 | Wrapper w{input}; |
121 | // expected-note@-1 {{Calling implicit copy constructor for 'Wrapper'}} |
122 | // expected-note@-2 {{Calling copy constructor for 'Dereferencer'}} |
123 | } |
124 | |
125 | void testMoveConstruction(MovableWrapper &&input) { |
126 | globalPtr = 0; |
127 | // expected-note@-1 {{Null pointer value stored to 'globalPtr'}} |
128 | MovableWrapper w{move(input)}; |
129 | // expected-note@-1 {{Calling defaulted move constructor for 'MovableWrapper'}} |
130 | } |
131 | |
132 | void testCopyAssignment(const Wrapper &input) { |
133 | Wrapper w; |
134 | globalPtr = 0; |
135 | // expected-note@-1 {{Null pointer value stored to 'globalPtr'}} |
136 | w = input; |
137 | // expected-note@-1 {{Calling implicit copy assignment operator for 'Wrapper'}} |
138 | // expected-note@-2 {{Calling copy assignment operator for 'Dereferencer'}} |
139 | } |
140 | |
141 | void testMoveAssignment(MovableWrapper &&input) { |
142 | MovableWrapper w; |
143 | globalPtr = 0; |
144 | // expected-note@-1 {{Null pointer value stored to 'globalPtr'}} |
145 | w = move(input); |
146 | // expected-note@-1 {{Calling defaulted move assignment operator for 'MovableWrapper'}} |
147 | } |
148 | |
149 | void testDestruction() { |
150 | Wrapper w; |
151 | globalPtr = 0; |
152 | // expected-note@-1 {{Null pointer value stored to 'globalPtr'}} |
153 | } |
154 | // expected-note@-1 {{Calling implicit destructor for 'Wrapper'}} |
155 | // expected-note@-2 {{Calling '~Dereferencer'}} |
156 | } |
157 | |
158 | namespace ReturnZeroNote { |
159 | int getZero() { |
160 | return 0; |
161 | // expected-note@-1 {{Returning zero}} |
162 | } |
163 | |
164 | const int &getZeroByRef() { |
165 | static int zeroVar; |
166 | zeroVar = 0; |
167 | // expected-note@-1 {{The value 0 is assigned to 'zeroVar'}} |
168 | return zeroVar; |
169 | // expected-note@-1 {{Returning zero (reference to 'zeroVar')}} |
170 | } |
171 | |
172 | void test() { |
173 | int problem = 1 / getZero(); // expected-warning {{Division by zero}} |
174 | // expected-note@-1 {{Calling 'getZero'}} |
175 | // expected-note@-2 {{Returning from 'getZero'}} |
176 | // expected-note@-3 {{Division by zero}} |
177 | } |
178 | |
179 | void testRef() { |
180 | int problem = 1 / getZeroByRef(); // expected-warning {{Division by zero}} |
181 | // expected-note@-1 {{Calling 'getZeroByRef'}} |
182 | // expected-note@-2 {{Returning from 'getZeroByRef'}} |
183 | // expected-note@-3 {{Division by zero}} |
184 | } |
185 | } |
186 | |
187 | int &returnNullReference() { |
188 | int *x = 0; |
189 | // expected-note@-1 {{'x' initialized to a null pointer value}} |
190 | return *x; // expected-warning{{Returning null reference}} |
191 | // expected-note@-1 {{Returning null reference}} |
192 | } |
193 | |
194 | struct FooWithInitializer { |
195 | int *ptr; |
196 | FooWithInitializer(int *p) : ptr(p) { // expected-note {{Null pointer value stored to 'f.ptr'}} |
197 | *ptr = 1; // expected-note {{Dereference of null pointer (loaded from field 'ptr')}} |
198 | // expected-warning@-1 {{Dereference of null pointer (loaded from field 'ptr')}} |
199 | } |
200 | }; |
201 | |
202 | void testPathNoteOnInitializer() { |
203 | int *p = 0; // expected-note {{'p' initialized to a null pointer value}} |
204 | |
205 | FooWithInitializer f(p); // expected-note {{Passing null pointer value via 1st parameter 'p'}} |
206 | // expected-note@-1 {{Calling constructor for 'FooWithInitializer'}} |
207 | } |
208 | |
209 | int testNonPrintableAssignment(int **p) { |
210 | int *&y = *p; // expected-note {{'y' initialized here}} |
211 | y = 0; // expected-note {{Storing null pointer value}} |
212 | return *y; // expected-warning {{Dereference of null pointer (loaded from variable 'y')}} |
213 | // expected-note@-1 {{Dereference of null pointer (loaded from variable 'y')}} |
214 | } |
215 | |
216 | struct Base { int *x; }; |
217 | struct Derived : public Base {}; |
218 | |
219 | void test(Derived d) { |
220 | d.x = 0; //expected-note {{Null pointer value stored to 'd.x'}} |
221 | *d.x = 1; // expected-warning {{Dereference of null pointer (loaded from field 'x')}} |
222 | // expected-note@-1 {{Dereference of null pointer (loaded from field 'x')}} |
223 | } |
224 | |
225 | struct Owner { |
226 | struct Wrapper { |
227 | int x; |
228 | }; |
229 | Wrapper *arr; |
230 | void testGetDerefExprOnMemberExprWithADot(); |
231 | }; |
232 | |
233 | void Owner::testGetDerefExprOnMemberExprWithADot() { |
234 | if (arr) // expected-note {{Assuming pointer value is null}} |
235 | // expected-note@-1 {{Taking false branch}} |
236 | ; |
237 | arr[1].x = 1; //expected-warning {{Dereference of null pointer}} |
238 | //expected-note@-1 {{Dereference of null pointer}} |
239 | } |
240 | |
241 | void testGetDerefExprOnMemberExprWithADot() { |
242 | Owner::Wrapper *arr; // expected-note {{'arr' declared without an initial value}} |
243 | arr[2].x = 1; // expected-warning {{Dereference of undefined pointer value}} |
244 | // expected-note@-1 {{Dereference of undefined pointer value}} |
245 | } |
246 | |
247 | |
248 | |
249 | class A { |
250 | public: |
251 | void bar() const {} |
252 | }; |
253 | const A& testDeclRefExprToReferenceInGetDerefExpr(const A *ptr) { |
254 | const A& val = *ptr; //expected-note {{'val' initialized here}} |
255 | |
256 | // This is not valid C++; if 'ptr' were null, creating 'ref' would be illegal. |
257 | // However, this is not checked at runtime, so this branch is actually |
258 | // possible. |
259 | if (&val == 0) { //expected-note {{Assuming pointer value is null}} |
260 | // expected-note@-1 {{Taking true branch}} |
261 | val.bar(); // expected-warning {{Called C++ object pointer is null}} |
262 | // expected-note@-1 {{Called C++ object pointer is null}} |
263 | } |
264 | |
265 | return val; |
266 | } |
267 | |
268 | int generateNoteOnDefaultArgument(int one, int two = 0) { |
269 | return one/two; // expected-warning {{Division by zero}} |
270 | // expected-note@-1 {{Division by zero}} |
271 | } |
272 | int callGenerateNoteOnDefaultArgument(int o) { |
273 | return generateNoteOnDefaultArgument(o); //expected-note{{Calling 'generateNoteOnDefaultArgument'}} |
274 | //expected-note@-1 {{Passing the value 0 via 2nd parameter 'two'}} |
275 | } |
276 | |
277 | namespace PR17746 { |
278 | class Inner { |
279 | public: |
280 | ~Inner() { |
281 | *(volatile int *)0 = 1; // expected-warning {{Dereference of null pointer}} |
282 | // expected-note@-1 {{Dereference of null pointer}} |
283 | } |
284 | }; |
285 | |
286 | class Outer { |
287 | public: |
288 | Inner *inner; |
289 | ~Outer() { |
290 | delete inner; |
291 | // expected-note@-1 {{Calling '~Inner'}} |
292 | } |
293 | }; |
294 | |
295 | void test(Outer *outer) { |
296 | delete outer; |
297 | // expected-note@-1 {{Calling '~Outer'}} |
298 | } |
299 | } |
300 | |
301 | |