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   P->foo(); // No warning.
45 }
46 
47 void derefOfUnknown(std::unique_ptr<A> P) {
48   P->foo(); // No warning.
49 }
50 
51 void derefAfterDefaultCtr() {
52   std::unique_ptr<A> P;
53   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
54 }
55 
56 void derefAfterCtrWithNull() {
57   std::unique_ptr<A> P(nullptr);
58   *P; // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
59 }
60 
61 void derefAfterCtrWithNullVariable() {
62   A *InnerPtr = nullptr;
63   std::unique_ptr<A> P(InnerPtr);
64   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
65 }
66 
67 void derefAfterRelease() {
68   std::unique_ptr<A> P(new A());
69   P.release();
70   clang_analyzer_numTimesReached(); // expected-warning {{1}}
71   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
72 }
73 
74 void derefAfterReset() {
75   std::unique_ptr<A> P(new A());
76   P.reset();
77   clang_analyzer_numTimesReached(); // expected-warning {{1}}
78   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
79 }
80 
81 void derefAfterResetWithNull() {
82   std::unique_ptr<A> P(new A());
83   P.reset(nullptr);
84   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
85 }
86 
87 void derefAfterResetWithNonNull() {
88   std::unique_ptr<A> P;
89   P.reset(new A());
90   P->foo(); // No warning.
91 }
92 
93 void derefAfterReleaseAndResetWithNonNull() {
94   std::unique_ptr<A> P(new A());
95   P.release();
96   P.reset(new A());
97   P->foo(); // No warning.
98 }
99 
100 void derefOnReleasedNullRawPtr() {
101   std::unique_ptr<A> P;
102   A *AP = P.release();
103   AP->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}}
104 }
105 
106 void derefOnReleasedValidRawPtr() {
107   std::unique_ptr<A> P(new A());
108   A *AP = P.release();
109   AP->foo(); // No warning.
110 }
111 
112 void pass_smart_ptr_by_ref(std::unique_ptr<A> &a);
113 void pass_smart_ptr_by_const_ref(const std::unique_ptr<A> &a);
114 void pass_smart_ptr_by_rvalue_ref(std::unique_ptr<A> &&a);
115 void pass_smart_ptr_by_const_rvalue_ref(const std::unique_ptr<A> &&a);
116 void pass_smart_ptr_by_ptr(std::unique_ptr<A> *a);
117 void pass_smart_ptr_by_const_ptr(const std::unique_ptr<A> *a);
118 
119 void regioninvalidationTest() {
120   {
121     std::unique_ptr<A> P;
122     pass_smart_ptr_by_ref(P);
123     P->foo(); // no-warning
124   }
125   {
126     std::unique_ptr<A> P;
127     pass_smart_ptr_by_const_ref(P);
128     P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
129   }
130   {
131     std::unique_ptr<A> P;
132     pass_smart_ptr_by_rvalue_ref(std::move(P));
133     P->foo(); // no-warning
134   }
135   {
136     std::unique_ptr<A> P;
137     pass_smart_ptr_by_const_rvalue_ref(std::move(P));
138     P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
139   }
140   {
141     std::unique_ptr<A> P;
142     pass_smart_ptr_by_ptr(&P);
143     P->foo();
144   }
145   {
146     std::unique_ptr<A> P;
147     pass_smart_ptr_by_const_ptr(&P);
148     P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
149   }
150 }
151 
152 struct StructWithSmartPtr {
153   std::unique_ptr<A> P;
154 };
155 
156 void pass_struct_with_smart_ptr_by_ref(StructWithSmartPtr &a);
157 void pass_struct_with_smart_ptr_by_const_ref(const StructWithSmartPtr &a);
158 void pass_struct_with_smart_ptr_by_rvalue_ref(StructWithSmartPtr &&a);
159 void pass_struct_with_smart_ptr_by_const_rvalue_ref(const StructWithSmartPtr &&a);
160 void pass_struct_with_smart_ptr_by_ptr(StructWithSmartPtr *a);
161 void pass_struct_with_smart_ptr_by_const_ptr(const StructWithSmartPtr *a);
162 
163 void regioninvalidationTestWithinStruct() {
164   {
165     StructWithSmartPtr S;
166     pass_struct_with_smart_ptr_by_ref(S);
167     S.P->foo(); // no-warning
168   }
169   {
170     StructWithSmartPtr S;
171     pass_struct_with_smart_ptr_by_const_ref(S);
172     S.P->foo(); // expected-warning {{Dereference of null smart pointer 'S.P' [alpha.cplusplus.SmartPtr]}}
173   }
174   {
175     StructWithSmartPtr S;
176     pass_struct_with_smart_ptr_by_rvalue_ref(std::move(S));
177     S.P->foo(); // no-warning
178   }
179   {
180     StructWithSmartPtr S;
181     pass_struct_with_smart_ptr_by_const_rvalue_ref(std::move(S));
182     S.P->foo(); // expected-warning {{Dereference of null smart pointer 'S.P' [alpha.cplusplus.SmartPtr]}}
183   }
184   {
185     StructWithSmartPtr S;
186     pass_struct_with_smart_ptr_by_ptr(&S);
187     S.P->foo();
188   }
189   {
190     StructWithSmartPtr S;
191     pass_struct_with_smart_ptr_by_const_ptr(&S);
192     S.P->foo(); // expected-warning {{Dereference of null smart pointer 'S.P' [alpha.cplusplus.SmartPtr]}}
193   }
194 }
195 
196 void derefAfterAssignment() {
197   {
198     std::unique_ptr<A> P(new A());
199     std::unique_ptr<A> Q;
200     Q = std::move(P);
201     Q->foo(); // no-warning
202   }
203   {
204     std::unique_ptr<A> P;
205     std::unique_ptr<A> Q;
206     Q = std::move(P);
207     // TODO: Fix test with expecting warning after '=' operator overloading modeling.
208     Q->foo(); // no-warning
209   }
210 }
211 
212 void derefOnSwappedNullPtr() {
213   std::unique_ptr<A> P(new A());
214   std::unique_ptr<A> PNull;
215   P.swap(PNull);
216   PNull->foo(); // No warning.
217   (*P).foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
218 }
219 
220 void derefOnStdSwappedNullPtr() {
221   std::unique_ptr<A> P;
222   std::unique_ptr<A> PNull;
223   std::swap(P, PNull);
224   PNull->foo(); // expected-warning {{Dereference of null smart pointer 'PNull' [alpha.cplusplus.SmartPtr]}}
225   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
226 }
227 
228 void derefOnSwappedValidPtr() {
229   std::unique_ptr<A> P(new A());
230   std::unique_ptr<A> PValid(new A());
231   P.swap(PValid);
232   (*P).foo(); // No warning.
233   PValid->foo(); // No warning.
234   std::swap(P, PValid);
235   P->foo(); // No warning.
236   PValid->foo(); // No warning.
237 }
238