1 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection\
2 // RUN:   -analyzer-checker cplusplus.Move,alpha.cplusplus.SmartPtr\
3 // RUN:   -analyzer-config cplusplus.SmartPtrModeling:ModelSmartPtrDereference=true\
4 // RUN:   -std=c++11 -verify %s
5 
6 #include "Inputs/system-header-simulator-cxx.h"
7 
8 void clang_analyzer_warnIfReached();
9 void clang_analyzer_numTimesReached();
10 void clang_analyzer_eval(bool);
11 
12 void derefAfterMove(std::unique_ptr<int> P) {
13   std::unique_ptr<int> Q = std::move(P);
14   if (Q)
15     clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
16   *Q.get() = 1; // no-warning
17   if (P)
18     clang_analyzer_warnIfReached(); // no-warning
19   // TODO: Report a null dereference (instead).
20   *P.get() = 1; // expected-warning {{Method called on moved-from object 'P'}}
21 }
22 
23 // Don't crash when attempting to model a call with unknown callee.
24 namespace testUnknownCallee {
25 struct S {
26   void foo();
27 };
28 void bar(S *s, void (S::*func)(void)) {
29   (s->*func)(); // no-crash
30 }
31 } // namespace testUnknownCallee
32 
33 class A {
34 public:
35   A(){};
36   void foo();
37 };
38 
39 A *return_null() {
40   return nullptr;
41 }
42 
43 void derefAfterValidCtr() {
44   std::unique_ptr<A> P(new A());
45   clang_analyzer_numTimesReached(); // expected-warning {{1}}
46   P->foo(); // No warning.
47 }
48 
49 void derefOfUnknown(std::unique_ptr<A> P) {
50   P->foo(); // No warning.
51 }
52 
53 void derefAfterDefaultCtr() {
54   std::unique_ptr<A> P;
55   clang_analyzer_numTimesReached(); // expected-warning {{1}}
56   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
57 }
58 
59 void derefAfterCtrWithNull() {
60   std::unique_ptr<A> P(nullptr);
61   clang_analyzer_numTimesReached(); // expected-warning {{1}}
62   *P; // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
63 }
64 
65 void derefAfterCtrWithNullVariable() {
66   A *InnerPtr = nullptr;
67   std::unique_ptr<A> P(InnerPtr);
68   clang_analyzer_numTimesReached(); // expected-warning {{1}}
69   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
70 }
71 
72 void derefAfterRelease() {
73   std::unique_ptr<A> P(new A());
74   P.release();
75   clang_analyzer_numTimesReached(); // expected-warning {{1}}
76   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
77 }
78 
79 void derefAfterReset() {
80   std::unique_ptr<A> P(new A());
81   P.reset();
82   clang_analyzer_numTimesReached(); // expected-warning {{1}}
83   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
84 }
85 
86 void derefAfterResetWithNull() {
87   std::unique_ptr<A> P(new A());
88   P.reset(nullptr);
89   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
90 }
91 
92 void derefAfterResetWithNonNull() {
93   std::unique_ptr<A> P;
94   P.reset(new A());
95   clang_analyzer_numTimesReached(); // expected-warning {{1}}
96   P->foo(); // No warning.
97 }
98 
99 void derefAfterReleaseAndResetWithNonNull() {
100   std::unique_ptr<A> P(new A());
101   P.release();
102   P.reset(new A());
103   P->foo(); // No warning.
104 }
105 
106 void derefOnReleasedNullRawPtr() {
107   std::unique_ptr<A> P;
108   A *AP = P.release();
109   AP->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}}
110 }
111 
112 void derefOnReleasedValidRawPtr() {
113   std::unique_ptr<A> P(new A());
114   A *AP = P.release();
115   AP->foo(); // No warning.
116 }
117 
118 void pass_smart_ptr_by_ref(std::unique_ptr<A> &a);
119 void pass_smart_ptr_by_const_ref(const std::unique_ptr<A> &a);
120 void pass_smart_ptr_by_rvalue_ref(std::unique_ptr<A> &&a);
121 void pass_smart_ptr_by_const_rvalue_ref(const std::unique_ptr<A> &&a);
122 void pass_smart_ptr_by_ptr(std::unique_ptr<A> *a);
123 void pass_smart_ptr_by_const_ptr(const std::unique_ptr<A> *a);
124 
125 void regioninvalidationWithPassByRef() {
126   std::unique_ptr<A> P;
127   pass_smart_ptr_by_ref(P);
128   P->foo(); // no-warning
129 }
130 
131 void regioninvalidationWithPassByCostRef() {
132   std::unique_ptr<A> P;
133   pass_smart_ptr_by_const_ref(P);
134   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
135 }
136 
137 void regioninvalidationWithPassByRValueRef() {
138   std::unique_ptr<A> P;
139   pass_smart_ptr_by_rvalue_ref(std::move(P));
140   P->foo(); // no-warning
141 }
142 
143 void regioninvalidationWithPassByConstRValueRef() {
144   std::unique_ptr<A> P;
145   pass_smart_ptr_by_const_rvalue_ref(std::move(P));
146   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
147 }
148 
149 void regioninvalidationWithPassByPtr() {
150   std::unique_ptr<A> P;
151   pass_smart_ptr_by_ptr(&P);
152   P->foo();
153 }
154 
155 void regioninvalidationWithPassByConstPtr() {
156   std::unique_ptr<A> P;
157   pass_smart_ptr_by_const_ptr(&P);
158   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
159 }
160 
161 struct StructWithSmartPtr {
162   std::unique_ptr<A> P;
163 };
164 
165 void pass_struct_with_smart_ptr_by_ref(StructWithSmartPtr &a);
166 void pass_struct_with_smart_ptr_by_const_ref(const StructWithSmartPtr &a);
167 void pass_struct_with_smart_ptr_by_rvalue_ref(StructWithSmartPtr &&a);
168 void pass_struct_with_smart_ptr_by_const_rvalue_ref(const StructWithSmartPtr &&a);
169 void pass_struct_with_smart_ptr_by_ptr(StructWithSmartPtr *a);
170 void pass_struct_with_smart_ptr_by_const_ptr(const StructWithSmartPtr *a);
171 
172 void regioninvalidationWithinStructPassByRef() {
173   StructWithSmartPtr S;
174   pass_struct_with_smart_ptr_by_ref(S);
175   S.P->foo(); // no-warning
176 }
177 
178 void regioninvalidationWithinStructPassByConstRef() {
179   StructWithSmartPtr S;
180   pass_struct_with_smart_ptr_by_const_ref(S);
181   S.P->foo(); // expected-warning {{Dereference of null smart pointer 'S.P' [alpha.cplusplus.SmartPtr]}}
182 }
183 
184 void regioninvalidationWithinStructPassByRValueRef() {
185   StructWithSmartPtr S;
186   pass_struct_with_smart_ptr_by_rvalue_ref(std::move(S));
187   S.P->foo(); // no-warning
188 }
189 
190 void regioninvalidationWithinStructPassByConstRValueRef() {
191   StructWithSmartPtr S;
192   pass_struct_with_smart_ptr_by_const_rvalue_ref(std::move(S));
193   S.P->foo(); // expected-warning {{Dereference of null smart pointer 'S.P' [alpha.cplusplus.SmartPtr]}}
194 }
195 
196 void regioninvalidationWithinStructPassByPtr() {
197   StructWithSmartPtr S;
198   pass_struct_with_smart_ptr_by_ptr(&S);
199   S.P->foo(); // no-warning
200 }
201 
202 void regioninvalidationWithinStructPassByConstPtr() {
203   StructWithSmartPtr S;
204   pass_struct_with_smart_ptr_by_const_ptr(&S);
205   S.P->foo(); // expected-warning {{Dereference of null smart pointer 'S.P' [alpha.cplusplus.SmartPtr]}}
206 }
207 
208 void derefAfterAssignment() {
209   {
210     std::unique_ptr<A> P(new A());
211     std::unique_ptr<A> Q;
212     Q = std::move(P);
213     Q->foo(); // no-warning
214   }
215   {
216     std::unique_ptr<A> P;
217     std::unique_ptr<A> Q;
218     Q = std::move(P);
219     // TODO: Fix test with expecting warning after '=' operator overloading modeling.
220     Q->foo(); // no-warning
221   }
222 }
223 
224 void derefOnSwappedNullPtr() {
225   std::unique_ptr<A> P(new A());
226   std::unique_ptr<A> PNull;
227   P.swap(PNull);
228   PNull->foo(); // No warning.
229   (*P).foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
230 }
231 
232 void derefOnFirstStdSwappedNullPtr() {
233   std::unique_ptr<A> P;
234   std::unique_ptr<A> PNull;
235   std::swap(P, PNull);
236   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
237 }
238 
239 void derefOnSecondStdSwappedNullPtr() {
240   std::unique_ptr<A> P;
241   std::unique_ptr<A> PNull;
242   std::swap(P, PNull);
243   PNull->foo(); // expected-warning {{Dereference of null smart pointer 'PNull' [alpha.cplusplus.SmartPtr]}}
244 }
245 
246 void derefOnSwappedValidPtr() {
247   std::unique_ptr<A> P(new A());
248   std::unique_ptr<A> PValid(new A());
249   P.swap(PValid);
250   (*P).foo(); // No warning.
251   PValid->foo(); // No warning.
252   std::swap(P, PValid);
253   P->foo(); // No warning.
254   PValid->foo(); // No warning.
255 }
256 
257 void derefOnRawPtrFromGetOnNullPtr() {
258   std::unique_ptr<A> P;
259   P.get()->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}}
260 }
261 
262 void derefOnRawPtrFromGetOnValidPtr() {
263   std::unique_ptr<A> P(new A());
264   P.get()->foo(); // No warning.
265 }
266 
267 void derefOnRawPtrFromGetOnUnknownPtr(std::unique_ptr<A> P) {
268   P.get()->foo(); // No warning.
269 }
270 
271 void derefOnRawPtrFromMultipleGetOnUnknownPtr(std::unique_ptr<A> P) {
272   A *X = P.get();
273   A *Y = P.get();
274   clang_analyzer_eval(X == Y); // expected-warning{{TRUE}}
275   if (!X) {
276     Y->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}}
277   }
278 }
279