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