1 | // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s |
2 | |
3 | void clang_analyzer_eval(bool); |
4 | |
5 | struct A { |
6 | // This conversion operator allows implicit conversion to bool but not to other integer types. |
7 | typedef A * (A::*MemberPointer); |
8 | operator MemberPointer() const { return m_ptr ? &A::m_ptr : 0; } |
9 | |
10 | A *m_ptr; |
11 | |
12 | A *getPtr(); |
13 | typedef A * (A::*MemberFnPointer)(void); |
14 | }; |
15 | |
16 | void testConditionalUse() { |
17 | A obj; |
18 | |
19 | obj.m_ptr = &obj; |
20 | clang_analyzer_eval(obj.m_ptr); // expected-warning{{TRUE}} |
21 | clang_analyzer_eval(&A::m_ptr); // expected-warning{{TRUE}} |
22 | clang_analyzer_eval(obj); // expected-warning{{TRUE}} |
23 | |
24 | obj.m_ptr = 0; |
25 | clang_analyzer_eval(obj.m_ptr); // expected-warning{{FALSE}} |
26 | clang_analyzer_eval(A::MemberPointer(0)); // expected-warning{{FALSE}} |
27 | clang_analyzer_eval(obj); // expected-warning{{FALSE}} |
28 | |
29 | clang_analyzer_eval(&A::getPtr); // expected-warning{{TRUE}} |
30 | clang_analyzer_eval(A::MemberFnPointer(0)); // expected-warning{{FALSE}} |
31 | } |
32 | |
33 | |
34 | void testComparison() { |
35 | clang_analyzer_eval(&A::getPtr == &A::getPtr); // expected-warning{{TRUE}} |
36 | clang_analyzer_eval(&A::getPtr == 0); // expected-warning{{FALSE}} |
37 | |
38 | clang_analyzer_eval(&A::m_ptr == &A::m_ptr); // expected-warning{{TRUE}} |
39 | } |
40 | |
41 | namespace PR15742 { |
42 | template <class _T1, class _T2> struct A { |
43 | A (const _T1 &, const _T2 &); |
44 | }; |
45 | |
46 | typedef void *NPIdentifier; |
47 | |
48 | template <class T> class B { |
49 | public: |
50 | typedef A<NPIdentifier, bool (T::*) (const NPIdentifier *, unsigned, |
51 | NPIdentifier *)> MethodMapMember; |
52 | }; |
53 | |
54 | class C : public B<C> { |
55 | public: |
56 | bool Find(const NPIdentifier *, unsigned, NPIdentifier *); |
57 | }; |
58 | |
59 | void InitStaticData () { |
60 | C::MethodMapMember(0, &C::Find); // don't crash |
61 | } |
62 | } |
63 | |
64 | bool testDereferencing() { |
65 | A obj; |
66 | obj.m_ptr = 0; |
67 | |
68 | A::MemberPointer member = &A::m_ptr; |
69 | |
70 | clang_analyzer_eval(obj.*member == 0); // expected-warning{{TRUE}} |
71 | |
72 | member = 0; |
73 | |
74 | return obj.*member; // expected-warning{{The result of the '.*' expression is undefined}} |
75 | } |
76 | |
77 | namespace testPointerToMemberFunction { |
78 | struct A { |
79 | virtual int foo() { return 1; } |
80 | int bar() { return 2; } |
81 | int static staticMemberFunction(int p) { return p + 1; }; |
82 | }; |
83 | |
84 | struct B : public A { |
85 | virtual int foo() { return 3; } |
86 | }; |
87 | |
88 | typedef int (A::*AFnPointer)(); |
89 | typedef int (B::*BFnPointer)(); |
90 | |
91 | void testPointerToMemberCasts() { |
92 | AFnPointer AFP = &A::bar; |
93 | BFnPointer StaticCastedBase2Derived = static_cast<BFnPointer>(&A::bar), |
94 | CCastedBase2Derived = (BFnPointer) (&A::bar); |
95 | A a; |
96 | B b; |
97 | |
98 | clang_analyzer_eval((a.*AFP)() == 2); // expected-warning{{TRUE}} |
99 | clang_analyzer_eval((b.*StaticCastedBase2Derived)() == 2); // expected-warning{{TRUE}} |
100 | clang_analyzer_eval(((b.*CCastedBase2Derived)() == 2)); // expected-warning{{TRUE}} |
101 | } |
102 | |
103 | void testPointerToMemberVirtualCall() { |
104 | A a; |
105 | B b; |
106 | A *APtr = &a; |
107 | AFnPointer AFP = &A::foo; |
108 | |
109 | clang_analyzer_eval((APtr->*AFP)() == 1); // expected-warning{{TRUE}} |
110 | |
111 | APtr = &b; |
112 | |
113 | clang_analyzer_eval((APtr->*AFP)() == 3); // expected-warning{{TRUE}} |
114 | } |
115 | |
116 | void testPointerToStaticMemberCall() { |
117 | int (*fPtr)(int) = &A::staticMemberFunction; |
118 | if (fPtr != 0) { // no-crash |
119 | clang_analyzer_eval(fPtr(2) == 3); // expected-warning{{TRUE}} |
120 | } |
121 | } |
122 | } // end of testPointerToMemberFunction namespace |
123 | |
124 | namespace testPointerToMemberData { |
125 | struct A { |
126 | int i; |
127 | static int j; |
128 | }; |
129 | |
130 | void testPointerToMemberData() { |
131 | int A::*AMdPointer = &A::i; |
132 | A a; |
133 | |
134 | a.i = 42; |
135 | a.*AMdPointer += 1; |
136 | |
137 | clang_analyzer_eval(a.i == 43); // expected-warning{{TRUE}} |
138 | |
139 | int *ptrToStaticField = &A::j; |
140 | if (ptrToStaticField != 0) { |
141 | *ptrToStaticField = 7; |
142 | clang_analyzer_eval(*ptrToStaticField == 7); // expected-warning{{TRUE}} |
143 | clang_analyzer_eval(A::j == 7); // expected-warning{{TRUE}} |
144 | } |
145 | } |
146 | } // end of testPointerToMemberData namespace |
147 | |
148 | namespace testPointerToMemberMiscCasts { |
149 | struct B { |
150 | int f; |
151 | }; |
152 | |
153 | struct D : public B { |
154 | int g; |
155 | }; |
156 | |
157 | void foo() { |
158 | D d; |
159 | d.f = 7; |
160 | |
161 | int B::* pfb = &B::f; |
162 | int D::* pfd = pfb; |
163 | int v = d.*pfd; |
164 | |
165 | clang_analyzer_eval(v == 7); // expected-warning{{TRUE}} |
166 | } |
167 | } // end of testPointerToMemberMiscCasts namespace |
168 | |
169 | namespace testPointerToMemberMiscCasts2 { |
170 | struct B { |
171 | int f; |
172 | }; |
173 | struct L : public B { }; |
174 | struct R : public B { }; |
175 | struct D : public L, R { }; |
176 | |
177 | void foo() { |
178 | D d; |
179 | |
180 | int B::* pb = &B::f; |
181 | int L::* pl = pb; |
182 | int R::* pr = pb; |
183 | |
184 | int D::* pdl = pl; |
185 | int D::* pdr = pr; |
186 | |
187 | clang_analyzer_eval(pdl == pdr); // expected-warning{{FALSE}} |
188 | clang_analyzer_eval(pb == pl); // expected-warning{{TRUE}} |
189 | } |
190 | } // end of testPointerToMemberMiscCasts2 namespace |
191 | |
192 | namespace testPointerToMemberDiamond { |
193 | struct B { |
194 | int f; |
195 | }; |
196 | struct L1 : public B { }; |
197 | struct R1 : public B { }; |
198 | struct M : public L1, R1 { }; |
199 | struct L2 : public M { }; |
200 | struct R2 : public M { }; |
201 | struct D2 : public L2, R2 { }; |
202 | |
203 | void diamond() { |
204 | M m; |
205 | |
206 | static_cast<L1 *>(&m)->f = 7; |
207 | static_cast<R1 *>(&m)->f = 16; |
208 | |
209 | int L1::* pl1 = &B::f; |
210 | int M::* pm_via_l1 = pl1; |
211 | |
212 | int R1::* pr1 = &B::f; |
213 | int M::* pm_via_r1 = pr1; |
214 | |
215 | clang_analyzer_eval(m.*(pm_via_l1) == 7); // expected-warning {{TRUE}} |
216 | clang_analyzer_eval(m.*(pm_via_r1) == 16); // expected-warning {{TRUE}} |
217 | } |
218 | |
219 | void double_diamond() { |
220 | D2 d2; |
221 | |
222 | static_cast<L1 *>(static_cast<L2 *>(&d2))->f = 1; |
223 | static_cast<L1 *>(static_cast<R2 *>(&d2))->f = 2; |
224 | static_cast<R1 *>(static_cast<L2 *>(&d2))->f = 3; |
225 | static_cast<R1 *>(static_cast<R2 *>(&d2))->f = 4; |
226 | |
227 | clang_analyzer_eval(d2.*(static_cast<int D2::*>(static_cast<int L2::*>(static_cast<int L1::*>(&B::f)))) == 1); // expected-warning {{TRUE}} |
228 | clang_analyzer_eval(d2.*(static_cast<int D2::*>(static_cast<int R2::*>(static_cast<int L1::*>(&B::f)))) == 2); // expected-warning {{TRUE}} |
229 | clang_analyzer_eval(d2.*(static_cast<int D2::*>(static_cast<int L2::*>(static_cast<int R1::*>(&B::f)))) == 3); // expected-warning {{TRUE}} |
230 | clang_analyzer_eval(d2.*(static_cast<int D2::*>(static_cast<int R2::*>(static_cast<int R1::*>(&B::f)))) == 4); // expected-warning {{TRUE}} |
231 | } |
232 | } // end of testPointerToMemberDiamond namespace |
233 | |
234 | namespace testAnonymousMember { |
235 | struct A { |
236 | struct { |
237 | int x; |
238 | }; |
239 | struct { |
240 | struct { |
241 | int y; |
242 | }; |
243 | }; |
244 | struct { |
245 | union { |
246 | int z; |
247 | }; |
248 | }; |
249 | }; |
250 | |
251 | void test() { |
252 | clang_analyzer_eval(&A::x); // expected-warning{{TRUE}} |
253 | clang_analyzer_eval(&A::y); // expected-warning{{TRUE}} |
254 | clang_analyzer_eval(&A::z); // expected-warning{{TRUE}} |
255 | |
256 | // FIXME: These should be true. |
257 | int A::*l = &A::x, A::*m = &A::y, A::*n = &A::z; |
258 | clang_analyzer_eval(l); // expected-warning{{UNKNOWN}} |
259 | clang_analyzer_eval(m); // expected-warning{{UNKNOWN}} |
260 | clang_analyzer_eval(n); // expected-warning{{UNKNOWN}} |
261 | |
262 | // FIXME: These should be true as well. |
263 | A a; |
264 | a.x = 1; |
265 | clang_analyzer_eval(a.*l == 1); // expected-warning{{UNKNOWN}} |
266 | a.y = 2; |
267 | clang_analyzer_eval(a.*m == 2); // expected-warning{{UNKNOWN}} |
268 | a.z = 3; |
269 | clang_analyzer_eval(a.*n == 3); // expected-warning{{UNKNOWN}} |
270 | } |
271 | } // end of testAnonymousMember namespace |
272 | |