1 | // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\ |
2 | // RUN: -analyzer-checker=debug.ExprInspection -verify\ |
3 | // RUN: -x c %s |
4 | // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\ |
5 | // RUN: -analyzer-checker=debug.ExprInspection -verify\ |
6 | // RUN: -x c++ -std=c++14 %s |
7 | // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\ |
8 | // RUN: -analyzer-checker=debug.ExprInspection -verify\ |
9 | // RUN: -x c++ -std=c++17 %s |
10 | // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\ |
11 | // RUN: -analyzer-checker=debug.ExprInspection -verify\ |
12 | // RUN: -DINLINE -x c %s |
13 | // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\ |
14 | // RUN: -analyzer-checker=debug.ExprInspection -verify\ |
15 | // RUN: -DINLINE -x c++ -std=c++14 %s |
16 | // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\ |
17 | // RUN: -analyzer-checker=debug.ExprInspection -verify\ |
18 | // RUN: -DINLINE -x c++ -std=c++17 %s |
19 | |
20 | void clang_analyzer_eval(int); |
21 | |
22 | struct S { |
23 | int field; |
24 | |
25 | #if __cplusplus |
26 | const struct S *getThis() const { return this; } |
27 | const struct S *operator +() const { return this; } |
28 | |
29 | bool check() const { return this == this; } |
30 | bool operator !() const { return this != this; } |
31 | |
32 | int operator *() const { return field; } |
33 | #endif |
34 | }; |
35 | |
36 | #if __cplusplus |
37 | const struct S *operator -(const struct S &s) { return &s; } |
38 | bool operator ~(const struct S &s) { return (&s) != &s; } |
39 | #endif |
40 | |
41 | |
42 | #ifdef INLINE |
43 | struct S getS() { |
44 | struct S s = { 42 }; |
45 | return s; |
46 | } |
47 | #else |
48 | struct S getS(); |
49 | #endif |
50 | |
51 | |
52 | void testAssignment() { |
53 | struct S s = getS(); |
54 | |
55 | if (s.field != 42) return; |
56 | clang_analyzer_eval(s.field == 42); // expected-warning{{TRUE}} |
57 | |
58 | s.field = 0; |
59 | clang_analyzer_eval(s.field == 0); // expected-warning{{TRUE}} |
60 | |
61 | #if __cplusplus |
62 | clang_analyzer_eval(s.getThis() == &s); // expected-warning{{TRUE}} |
63 | clang_analyzer_eval(+s == &s); // expected-warning{{TRUE}} |
64 | clang_analyzer_eval(-s == &s); // expected-warning{{TRUE}} |
65 | |
66 | clang_analyzer_eval(s.check()); // expected-warning{{TRUE}} |
67 | clang_analyzer_eval(!s); // expected-warning{{FALSE}} |
68 | clang_analyzer_eval(~s); // expected-warning{{FALSE}} |
69 | |
70 | clang_analyzer_eval(*s == 0); // expected-warning{{TRUE}} |
71 | #endif |
72 | } |
73 | |
74 | |
75 | void testImmediateUse() { |
76 | int x = getS().field; |
77 | |
78 | if (x != 42) return; |
79 | clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} |
80 | |
81 | #if __cplusplus |
82 | clang_analyzer_eval((void *)getS().getThis() == (void *)&x); // expected-warning{{FALSE}} |
83 | clang_analyzer_eval((void *)+getS() == (void *)&x); // expected-warning{{FALSE}} |
84 | clang_analyzer_eval((void *)-getS() == (void *)&x); // expected-warning{{FALSE}} |
85 | |
86 | clang_analyzer_eval(getS().check()); // expected-warning{{TRUE}} |
87 | clang_analyzer_eval(!getS()); // expected-warning{{FALSE}} |
88 | clang_analyzer_eval(~getS()); // expected-warning{{FALSE}} |
89 | #endif |
90 | } |
91 | |
92 | int getConstrainedField(struct S s) { |
93 | if (s.field != 42) return 42; |
94 | return s.field; |
95 | } |
96 | |
97 | int getAssignedField(struct S s) { |
98 | s.field = 42; |
99 | return s.field; |
100 | } |
101 | |
102 | void testArgument() { |
103 | clang_analyzer_eval(getConstrainedField(getS()) == 42); // expected-warning{{TRUE}} |
104 | clang_analyzer_eval(getAssignedField(getS()) == 42); // expected-warning{{TRUE}} |
105 | } |
106 | |
107 | void testImmediateUseParens() { |
108 | int x = ((getS())).field; |
109 | |
110 | if (x != 42) return; |
111 | clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} |
112 | |
113 | clang_analyzer_eval(getConstrainedField(((getS()))) == 42); // expected-warning{{TRUE}} |
114 | clang_analyzer_eval(getAssignedField(((getS()))) == 42); // expected-warning{{TRUE}} |
115 | |
116 | #if __cplusplus |
117 | clang_analyzer_eval(((getS())).check()); // expected-warning{{TRUE}} |
118 | clang_analyzer_eval(!((getS()))); // expected-warning{{FALSE}} |
119 | clang_analyzer_eval(~((getS()))); // expected-warning{{FALSE}} |
120 | #endif |
121 | } |
122 | |
123 | |
124 | //-------------------- |
125 | // C++-only tests |
126 | //-------------------- |
127 | |
128 | #if __cplusplus |
129 | void testReferenceAssignment() { |
130 | const S &s = getS(); |
131 | |
132 | if (s.field != 42) return; |
133 | clang_analyzer_eval(s.field == 42); // expected-warning{{TRUE}} |
134 | |
135 | clang_analyzer_eval(s.getThis() == &s); // expected-warning{{TRUE}} |
136 | clang_analyzer_eval(+s == &s); // expected-warning{{TRUE}} |
137 | |
138 | clang_analyzer_eval(s.check()); // expected-warning{{TRUE}} |
139 | clang_analyzer_eval(!s); // expected-warning{{FALSE}} |
140 | clang_analyzer_eval(~s); // expected-warning{{FALSE}} |
141 | |
142 | clang_analyzer_eval(*s == 42); // expected-warning{{TRUE}} |
143 | } |
144 | |
145 | |
146 | int getConstrainedFieldRef(const S &s) { |
147 | if (s.field != 42) return 42; |
148 | return s.field; |
149 | } |
150 | |
151 | bool checkThis(const S &s) { |
152 | return s.getThis() == &s; |
153 | } |
154 | |
155 | bool checkThisOp(const S &s) { |
156 | return +s == &s; |
157 | } |
158 | |
159 | bool checkThisStaticOp(const S &s) { |
160 | return -s == &s; |
161 | } |
162 | |
163 | void testReferenceArgument() { |
164 | clang_analyzer_eval(getConstrainedFieldRef(getS()) == 42); // expected-warning{{TRUE}} |
165 | clang_analyzer_eval(checkThis(getS())); // expected-warning{{TRUE}} |
166 | clang_analyzer_eval(checkThisOp(getS())); // expected-warning{{TRUE}} |
167 | clang_analyzer_eval(checkThisStaticOp(getS())); // expected-warning{{TRUE}} |
168 | } |
169 | |
170 | |
171 | int getConstrainedFieldOp(S s) { |
172 | if (*s != 42) return 42; |
173 | return *s; |
174 | } |
175 | |
176 | int getConstrainedFieldRefOp(const S &s) { |
177 | if (*s != 42) return 42; |
178 | return *s; |
179 | } |
180 | |
181 | void testImmediateUseOp() { |
182 | int x = *getS(); |
183 | if (x != 42) return; |
184 | clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} |
185 | |
186 | clang_analyzer_eval(getConstrainedFieldOp(getS()) == 42); // expected-warning{{TRUE}} |
187 | clang_analyzer_eval(getConstrainedFieldRefOp(getS()) == 42); // expected-warning{{TRUE}} |
188 | } |
189 | |
190 | namespace EmptyClass { |
191 | struct Base { |
192 | int& x; |
193 | |
194 | Base(int& x) : x(x) {} |
195 | }; |
196 | |
197 | struct Derived : public Base { |
198 | Derived(int& x) : Base(x) {} |
199 | |
200 | void operator=(int a) { x = a; } |
201 | }; |
202 | |
203 | Derived ref(int& a) { return Derived(a); } |
204 | |
205 | // There used to be a warning here, because analyzer treated Derived as empty. |
206 | int test() { |
207 | int a; |
208 | ref(a) = 42; |
209 | return a; // no warning |
210 | } |
211 | } |
212 | |
213 | #if __cplusplus >= 201703L |
214 | namespace aggregate_inheritance_cxx17 { |
215 | struct A { |
216 | int x; |
217 | }; |
218 | |
219 | struct B { |
220 | int y; |
221 | }; |
222 | |
223 | struct C: B { |
224 | int z; |
225 | }; |
226 | |
227 | struct D: A, C { |
228 | int w; |
229 | }; |
230 | |
231 | void foo() { |
232 | D d{1, 2, 3, 4}; |
233 | clang_analyzer_eval(d.x == 1); // expected-warning{{TRUE}} |
234 | clang_analyzer_eval(d.y == 2); // expected-warning{{TRUE}} |
235 | clang_analyzer_eval(d.z == 3); // expected-warning{{TRUE}} |
236 | clang_analyzer_eval(d.w == 4); // expected-warning{{TRUE}} |
237 | } |
238 | } // namespace aggregate_inheritance_cxx17 |
239 | #endif |
240 | |
241 | namespace flex_array_inheritance_cxx17 { |
242 | struct A { |
243 | int flexible_array[]; |
244 | }; |
245 | |
246 | struct B { |
247 | long cookie; |
248 | }; |
249 | |
250 | struct C : B { |
251 | A a; |
252 | }; |
253 | |
254 | void foo() { |
255 | C c{}; // no-crash |
256 | } |
257 | } // namespace flex_array_inheritance_cxx17 |
258 | #endif |
259 | |