1 // RUN: %clang_analyze_cc1\
2 // RUN: -analyzer-checker=core,cplusplus.Move,alpha.cplusplus.SmartPtr,debug.ExprInspection\
3 // RUN: -analyzer-config cplusplus.SmartPtrModeling:ModelSmartPtrDereference=true\
4 // RUN: -analyzer-output=text -std=c++20 %s -verify=expected
5
6 // RUN: %clang_analyze_cc1\
7 // RUN: -analyzer-checker=core,cplusplus.Move,alpha.cplusplus.SmartPtr,debug.ExprInspection\
8 // RUN: -analyzer-config cplusplus.SmartPtrModeling:ModelSmartPtrDereference=true\
9 // RUN: -analyzer-output=text -std=c++11 %s -verify=expected
10
11 #include "Inputs/system-header-simulator-cxx.h"
12
13 void clang_analyzer_eval(bool);
14
15 class A {
16 public:
A()17 A(){};
18 void foo();
19 };
20
return_null()21 A *return_null() {
22 return nullptr;
23 }
24
derefAfterDefaultCtr()25 void derefAfterDefaultCtr() {
26 std::unique_ptr<A> P; // expected-note {{Default constructed smart pointer 'P' is null}}
27 P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
28 // expected-note@-1{{Dereference of null smart pointer 'P'}}
29 }
30
derefAfterCtrWithNull()31 void derefAfterCtrWithNull() {
32 A *NullInnerPtr = nullptr; // expected-note {{'NullInnerPtr' initialized to a null pointer value}}
33 std::unique_ptr<A> P(NullInnerPtr); // expected-note {{Smart pointer 'P' is constructed using a null value}}
34 *P; // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
35 // expected-note@-1{{Dereference of null smart pointer 'P'}}
36 }
37
derefAfterCtrWithNullVariable()38 void derefAfterCtrWithNullVariable() {
39 A *NullInnerPtr = nullptr; // expected-note {{'NullInnerPtr' initialized to a null pointer value}}
40 std::unique_ptr<A> P(NullInnerPtr); // expected-note {{Smart pointer 'P' is constructed using a null value}}
41 P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
42 // expected-note@-1{{Dereference of null smart pointer 'P'}}
43 }
44
derefAfterRelease()45 void derefAfterRelease() {
46 std::unique_ptr<A> P(new A()); // expected-note {{Smart pointer 'P' is constructed}}
47 // FIXME: should mark region as uninteresting after release, so above note will not be there
48 P.release(); // expected-note {{Smart pointer 'P' is released and set to null}}
49 P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
50 // expected-note@-1{{Dereference of null smart pointer 'P'}}
51 }
52
derefAfterReset()53 void derefAfterReset() {
54 std::unique_ptr<A> P(new A()); // expected-note {{Smart pointer 'P' is constructed}}
55 P.reset(); // expected-note {{Smart pointer 'P' reset using a null value}}
56 P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
57 // expected-note@-1{{Dereference of null smart pointer 'P'}}
58 }
59
derefAfterResetWithNull()60 void derefAfterResetWithNull() {
61 A *NullInnerPtr = nullptr; // expected-note {{'NullInnerPtr' initialized to a null pointer value}}
62 std::unique_ptr<A> P(new A()); // expected-note {{Smart pointer 'P' is constructed}}
63 P.reset(NullInnerPtr); // expected-note {{Smart pointer 'P' reset using a null value}}
64 P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
65 // expected-note@-1{{Dereference of null smart pointer 'P'}}
66 }
67
68 // FIXME: Fix this test when support is added for tracking raw pointer
69 // and mark the smart pointer as interesting based on that and add tags.
derefOnReleasedNullRawPtr()70 void derefOnReleasedNullRawPtr() {
71 std::unique_ptr<A> P; // FIXME: add note "Default constructed smart pointer 'P' is null"
72 A *AP = P.release(); // expected-note {{'AP' initialized to a null pointer value}}
73 AP->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}}
74 // expected-note@-1{{Called C++ object pointer is null}}
75 }
76
derefOnSwappedNullPtr()77 void derefOnSwappedNullPtr() {
78 std::unique_ptr<A> P(new A()); // expected-note {{Smart pointer 'P' is constructed}}
79 std::unique_ptr<A> PNull;
80 P.swap(PNull);
81 PNull->foo(); // No warning.
82 (*P).foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
83 // expected-note@-1{{Dereference of null smart pointer 'P'}}
84 }
85
derefOnStdSwappedNullPtr()86 void derefOnStdSwappedNullPtr() {
87 std::unique_ptr<A> P; // expected-note {{Default constructed smart pointer 'P' is null}}
88 std::unique_ptr<A> PNull;
89 std::swap(P, PNull);
90 P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
91 // expected-note@-1{{Dereference of null smart pointer 'P'}}
92 }
93
94 struct StructWithSmartPtr { // expected-note {{Default constructed smart pointer 'S.P' is null}}
95 std::unique_ptr<A> P;
96 };
97
derefAfterDefaultCtrInsideStruct()98 void derefAfterDefaultCtrInsideStruct() {
99 StructWithSmartPtr S; // expected-note {{Calling implicit default constructor for 'StructWithSmartPtr'}}
100 // expected-note@-1 {{Returning from default constructor for 'StructWithSmartPtr'}}
101 S.P->foo(); // expected-warning {{Dereference of null smart pointer 'S.P' [alpha.cplusplus.SmartPtr]}}
102 // expected-note@-1{{Dereference of null smart pointer 'S.P'}}
103 }
104
noNoteTagsForNonInterestingRegion()105 void noNoteTagsForNonInterestingRegion() {
106 std::unique_ptr<A> P; // expected-note {{Default constructed smart pointer 'P' is null}}
107 std::unique_ptr<A> P1; // No note.
108 std::unique_ptr<A> P2; // No note.
109 P1.release(); // No note.
110 P1.reset(); // No note.
111 P1.swap(P2); // No note.
112 P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
113 // expected-note@-1{{Dereference of null smart pointer 'P'}}
114 }
115
derefOnRawPtrFromGetOnNullPtr()116 void derefOnRawPtrFromGetOnNullPtr() {
117 std::unique_ptr<A> P; // FIXME: add note "Default constructed smart pointer 'P' is null"
118 P.get()->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}}
119 // expected-note@-1 {{Called C++ object pointer is null}}
120 }
121
derefOnRawPtrFromGetOnValidPtr()122 void derefOnRawPtrFromGetOnValidPtr() {
123 std::unique_ptr<A> P(new A());
124 P.get()->foo(); // No warning.
125 }
126
derefOnRawPtrFromGetOnUnknownPtr(std::unique_ptr<A> P)127 void derefOnRawPtrFromGetOnUnknownPtr(std::unique_ptr<A> P) {
128 P.get()->foo(); // No warning.
129 }
130
derefOnMovedFromValidPtr()131 void derefOnMovedFromValidPtr() {
132 std::unique_ptr<A> PToMove(new A()); // expected-note {{Smart pointer 'PToMove' is constructed}}
133 // FIXME: above note should go away once we fix marking region not interested.
134 std::unique_ptr<A> P;
135 P = std::move(PToMove); // expected-note {{Smart pointer 'PToMove' is null after being moved to 'P'}}
136 PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
137 // expected-note@-1 {{Dereference of null smart pointer 'PToMove'}}
138 }
139
derefOnMovedToNullPtr()140 void derefOnMovedToNullPtr() {
141 std::unique_ptr<A> PToMove(new A());
142 std::unique_ptr<A> P;
143 P = std::move(PToMove); // No note.
144 P->foo(); // No warning.
145 }
146
derefOnNullPtrGotMovedFromValidPtr()147 void derefOnNullPtrGotMovedFromValidPtr() {
148 std::unique_ptr<A> P(new A()); // expected-note {{Smart pointer 'P' is constructed}}
149 // FIXME: above note should go away once we fix marking region not interested.
150 std::unique_ptr<A> PToMove; // expected-note {{Default constructed smart pointer 'PToMove' is null}}
151 P = std::move(PToMove); // expected-note {{A null pointer value is moved to 'P'}}
152 P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
153 // expected-note@-1 {{Dereference of null smart pointer 'P'}}
154 }
155
derefOnMovedUnknownPtr(std::unique_ptr<A> PToMove)156 void derefOnMovedUnknownPtr(std::unique_ptr<A> PToMove) {
157 std::unique_ptr<A> P;
158 P = std::move(PToMove); // expected-note {{Smart pointer 'PToMove' is null after; previous value moved to 'P'}}
159 PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
160 // expected-note@-1 {{Dereference of null smart pointer 'PToMove'}}
161 }
162
derefOnAssignedNullPtrToNullSmartPtr()163 void derefOnAssignedNullPtrToNullSmartPtr() {
164 std::unique_ptr<A> P; // expected-note {{Default constructed smart pointer 'P' is null}}
165 P = nullptr; // expected-note {{Smart pointer 'P' is assigned to null}}
166 P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
167 // expected-note@-1 {{Dereference of null smart pointer 'P'}}
168 }
169
derefOnAssignedZeroToNullSmartPtr()170 void derefOnAssignedZeroToNullSmartPtr() {
171 std::unique_ptr<A> P(new A()); // expected-note {{Smart pointer 'P' is constructed}}
172 // FIXME: above note should go away once we fix marking region not interested.
173 P = 0; // expected-note {{Smart pointer 'P' is assigned to null}}
174 P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
175 // expected-note@-1 {{Dereference of null smart pointer 'P'}}
176 }
177
derefMoveConstructedWithNullPtr()178 void derefMoveConstructedWithNullPtr() {
179 std::unique_ptr<A> PToMove; // expected-note {{Default constructed smart pointer 'PToMove' is null}}
180 std::unique_ptr<A> P(std::move(PToMove)); // expected-note {{A null pointer value is moved to 'P'}}
181 P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
182 // expected-note@-1{{Dereference of null smart pointer 'P'}}
183 }
184
derefValidPtrMovedToConstruct()185 void derefValidPtrMovedToConstruct() {
186 std::unique_ptr<A> PToMove(new A()); // expected-note {{Smart pointer 'PToMove' is constructed}}
187 // FIXME: above note should go away once we fix marking region not interested.
188 std::unique_ptr<A> P(std::move(PToMove)); // expected-note {{Smart pointer 'PToMove' is null after being moved to 'P'}}
189 PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
190 // expected-note@-1{{Dereference of null smart pointer 'PToMove'}}
191 }
192
derefNullPtrMovedToConstruct()193 void derefNullPtrMovedToConstruct() {
194 std::unique_ptr<A> PToMove; // expected-note {{Default constructed smart pointer 'PToMove' is null}}
195 // FIXME: above note should go away once we fix marking region not interested.
196 std::unique_ptr<A> P(std::move(PToMove)); // expected-note {{Smart pointer 'PToMove' is null after being moved to 'P'}}
197 PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
198 // expected-note@-1{{Dereference of null smart pointer 'PToMove'}}
199 }
200
derefUnknownPtrMovedToConstruct(std::unique_ptr<A> PToMove)201 void derefUnknownPtrMovedToConstruct(std::unique_ptr<A> PToMove) {
202 std::unique_ptr<A> P(std::move(PToMove)); // expected-note {{Smart pointer 'PToMove' is null after; previous value moved to 'P'}}
203 PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
204 // expected-note@-1{{Dereference of null smart pointer 'PToMove'}}
205 }
206
derefConditionOnNullPtrFalseBranch()207 void derefConditionOnNullPtrFalseBranch() {
208 std::unique_ptr<A> P; // expected-note {{Default constructed smart pointer 'P' is null}}
209 if (P) { // expected-note {{Taking false branch}}
210 P->foo(); // No warning.
211 } else {
212 P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
213 // expected-note@-1{{Dereference of null smart pointer 'P'}}
214 }
215 }
216
derefConditionOnNullPtrTrueBranch()217 void derefConditionOnNullPtrTrueBranch() {
218 std::unique_ptr<A> P; // expected-note {{Default constructed smart pointer 'P' is null}}
219 if (!P) { // expected-note {{Taking true branch}}
220 P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
221 // expected-note@-1{{Dereference of null smart pointer 'P'}}
222 }
223 }
224
derefConditionOnValidPtrTrueBranch()225 void derefConditionOnValidPtrTrueBranch() {
226 std::unique_ptr<A> P(new A());
227 std::unique_ptr<A> PNull; // expected-note {{Default constructed smart pointer 'PNull' is null}}
228 if (P) { // expected-note {{Taking true branch}}
229 PNull->foo(); // expected-warning {{Dereference of null smart pointer 'PNull' [alpha.cplusplus.SmartPtr]}}
230 // expected-note@-1{{Dereference of null smart pointer 'PNull'}}
231 } else {
232 PNull->foo(); // No warning
233 }
234 }
235
derefConditionOnValidPtrFalseBranch()236 void derefConditionOnValidPtrFalseBranch() {
237 std::unique_ptr<A> P(new A());
238 std::unique_ptr<A> PNull; // expected-note {{Default constructed smart pointer 'PNull' is null}}
239 if (!P) { // expected-note {{Taking false branch}}
240 PNull->foo(); // No warning
241 } else {
242 PNull->foo(); // expected-warning {{Dereference of null smart pointer 'PNull' [alpha.cplusplus.SmartPtr]}}
243 // expected-note@-1{{Dereference of null smart pointer 'PNull'}}
244 }
245 }
246
derefConditionOnNotValidPtr()247 void derefConditionOnNotValidPtr() {
248 std::unique_ptr<A> P(new A());
249 std::unique_ptr<A> PNull;
250 if (!P)
251 PNull->foo(); // No warning.
252 }
253
derefConditionOnUnKnownPtrAssumeNull(std::unique_ptr<A> P)254 void derefConditionOnUnKnownPtrAssumeNull(std::unique_ptr<A> P) {
255 std::unique_ptr<A> PNull; // expected-note {{Default constructed smart pointer 'PNull' is null}}
256 if (!P) { // expected-note {{Taking true branch}}
257 // expected-note@-1{{Assuming smart pointer 'P' is null}}
258 PNull->foo(); // expected-warning {{Dereference of null smart pointer 'PNull' [alpha.cplusplus.SmartPtr]}}
259 // expected-note@-1{{Dereference of null smart pointer 'PNull'}}
260 }
261 }
262
derefConditionOnUnKnownPtrAssumeNonNull(std::unique_ptr<A> P)263 void derefConditionOnUnKnownPtrAssumeNonNull(std::unique_ptr<A> P) {
264 std::unique_ptr<A> PNull; // expected-note {{Default constructed smart pointer 'PNull' is null}}
265 if (P) { // expected-note {{Taking true branch}}
266 // expected-note@-1{{Assuming smart pointer 'P' is non-null}}
267 PNull->foo(); // expected-warning {{Dereference of null smart pointer 'PNull' [alpha.cplusplus.SmartPtr]}}
268 // expected-note@-1{{Dereference of null smart pointer 'PNull'}}
269 }
270 }
271
derefOnValidPtrAfterReset(std::unique_ptr<A> P)272 void derefOnValidPtrAfterReset(std::unique_ptr<A> P) {
273 P.reset(new A());
274 if (!P)
275 P->foo(); // No warning.
276 else
277 P->foo(); // No warning.
278 }
279
280 struct S {
281 std::unique_ptr<int> P;
282
fooS283 void foo() {
284 if (!P) { // No-note because foo() is pruned
285 return;
286 }
287 }
288
callingFooWithNullPointerS289 int callingFooWithNullPointer() {
290 foo(); // No note on Calling 'S::foo'
291 P.reset(new int(0)); // expected-note {{Assigning 0}}
292 return 1 / *(P.get()); // expected-warning {{Division by zero [core.DivideZero]}}
293 // expected-note@-1 {{Division by zero}}
294 }
295
callingFooWithValidPointerS296 int callingFooWithValidPointer() {
297 P.reset(new int(0)); // expected-note {{Assigning 0}}
298 foo(); // No note on Calling 'S::foo'
299 return 1 / *(P.get()); // expected-warning {{Division by zero [core.DivideZero]}}
300 // expected-note@-1 {{Division by zero}}
301 }
302
callingFooWithUnknownPointerS303 int callingFooWithUnknownPointer(std::unique_ptr<int> PUnknown) {
304 P.swap(PUnknown);
305 foo(); // No note on Calling 'S::foo'
306 P.reset(new int(0)); // expected-note {{Assigning 0}}
307 return 1 / *(P.get()); // expected-warning {{Division by zero [core.DivideZero]}}
308 // expected-note@-1 {{Division by zero}}
309 }
310 };
311
derefAfterBranchingOnUnknownInnerPtr(std::unique_ptr<A> P)312 void derefAfterBranchingOnUnknownInnerPtr(std::unique_ptr<A> P) {
313 A *RP = P.get();
314 if (!RP) { // expected-note {{Assuming 'RP' is null}}
315 // expected-note@-1 {{Taking true branch}}
316 P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
317 // expected-note@-1{{Dereference of null smart pointer 'P'}}
318 }
319 }
320
makeUniqueReturnsNonNullUniquePtr()321 void makeUniqueReturnsNonNullUniquePtr() {
322 auto P = std::make_unique<A>();
323 if (!P) { // expected-note {{Taking false branch}}
324 P->foo(); // should have no warning here, path is impossible
325 }
326 P.reset(); // expected-note {{Smart pointer 'P' reset using a null value}}
327 // Now P is null
328 if (!P) {
329 // expected-note@-1 {{Taking true branch}}
330 P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
331 // expected-note@-1{{Dereference of null smart pointer 'P'}}
332 }
333 }
334
335 #if __cplusplus >= 202002L
336
makeUniqueForOverwriteReturnsNullUniquePtr()337 void makeUniqueForOverwriteReturnsNullUniquePtr() {
338 auto P = std::make_unique_for_overwrite<A>();
339 if (!P) { // expected-note {{Taking false branch}}
340 P->foo(); // should have no warning here, path is impossible
341 }
342 P.reset(); // expected-note {{Smart pointer 'P' reset using a null value}}
343 // Now P is null
344 if (!P) {
345 // expected-note@-1 {{Taking true branch}}
346 P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
347 // expected-note@-1{{Dereference of null smart pointer 'P'}}
348 }
349 }
350
351 #endif
352
353 struct G {
354 int *p;
GG355 G(int *p): p(p) {}
~GG356 ~G() { *p = 0; }
357 };
358
foo()359 void foo() {
360 int x = 1;
361 {
362 auto P = std::make_unique<G>(&x);
363 // FIXME: There should not be a state split here, it should take the true path.
364 clang_analyzer_eval(*P->p == 1); // expected-warning {{TRUE}}
365 // expected-warning@-1 {{FALSE}}
366 // expected-note@-2 {{Assuming the condition is true}}
367 // expected-note@-3 {{Assuming the condition is false}}
368 // expected-note@-4 {{TRUE}}
369 // expected-note@-5 {{FALSE}}
370 // expected-note@-6 {{Assuming the condition is false}}
371 }
372 // FIXME: Should be fixed when unique_ptr desctructors are
373 // properly modelled. This includes modelling the call to
374 // the destructor of the inner pointer type.
375 clang_analyzer_eval(x == 0); // expected-warning {{FALSE}}
376 // expected-note@-1 {{FALSE}}
377 }
378