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