1 | // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-store=region -verify -Wno-null-dereference -Wno-tautological-undefined-compare -analyzer-config eagerly-assume=false %s |
2 | |
3 | void clang_analyzer_eval(bool); |
4 | |
5 | typedef typeof(sizeof(int)) size_t; |
6 | void malloc (size_t); |
7 | |
8 | void f1() { |
9 | int const &i = 3; |
10 | int b = i; |
11 | |
12 | int *p = 0; |
13 | |
14 | if (b != 3) |
15 | *p = 1; // no-warning |
16 | } |
17 | |
18 | char* ptr(); |
19 | char& ref(); |
20 | |
21 | // These next two tests just shouldn't crash. |
22 | char t1 () { |
23 | ref() = 'c'; |
24 | return '0'; |
25 | } |
26 | |
27 | // just a sanity test, the same behavior as t1() |
28 | char t2 () { |
29 | *ptr() = 'c'; |
30 | return '0'; |
31 | } |
32 | |
33 | // Each of the tests below is repeated with pointers as well as references. |
34 | // This is mostly a sanity check, but then again, both should work! |
35 | char t3 () { |
36 | char& r = ref(); |
37 | r = 'c'; // no-warning |
38 | if (r) return r; |
39 | return *(char*)0; // no-warning |
40 | } |
41 | |
42 | char t4 () { |
43 | char* p = ptr(); |
44 | *p = 'c'; // no-warning |
45 | if (*p) return *p; |
46 | return *(char*)0; // no-warning |
47 | } |
48 | |
49 | char t5 (char& r) { |
50 | r = 'c'; // no-warning |
51 | if (r) return r; |
52 | return *(char*)0; // no-warning |
53 | } |
54 | |
55 | char t6 (char* p) { |
56 | *p = 'c'; // no-warning |
57 | if (*p) return *p; |
58 | return *(char*)0; // no-warning |
59 | } |
60 | |
61 | |
62 | // PR13440 / <rdar://problem/11977113> |
63 | // Test that the array-to-pointer decay works for array references as well. |
64 | // More generally, when we want an lvalue for a reference field, we still need |
65 | // to do one level of load. |
66 | namespace PR13440 { |
67 | typedef int T[1]; |
68 | struct S { |
69 | T &x; |
70 | |
71 | int *m() { return x; } |
72 | }; |
73 | |
74 | struct S2 { |
75 | int (&x)[1]; |
76 | |
77 | int *m() { return x; } |
78 | |
79 | void testArrayToPointerDecayWithNonTypedValueRegion() { |
80 | int *p = x; |
81 | int *q = x; |
82 | clang_analyzer_eval(p[0] == q[0]); // expected-warning{{TRUE}} |
83 | } |
84 | |
85 | }; |
86 | |
87 | void test() { |
88 | int a[1]; |
89 | S s = { a }; |
90 | S2 s2 = { a }; |
91 | |
92 | if (s.x != a) return; |
93 | if (s2.x != a) return; |
94 | |
95 | a[0] = 42; |
96 | clang_analyzer_eval(s.x[0] == 42); // expected-warning{{TRUE}} |
97 | clang_analyzer_eval(s2.x[0] == 42); // expected-warning{{TRUE}} |
98 | } |
99 | } |
100 | |
101 | void testNullReference() { |
102 | int *x = 0; |
103 | int &y = *x; // expected-warning{{Dereference of null pointer}} |
104 | y = 5; |
105 | } |
106 | |
107 | void testRetroactiveNullReference(int *x) { |
108 | // According to the C++ standard, there is no such thing as a |
109 | // "null reference". So the 'if' statement ought to be dead code. |
110 | // However, Clang (and other compilers) don't actually check that a pointer |
111 | // value is non-null in the implementation of references, so it is possible |
112 | // to produce a supposed "null reference" at runtime. The analyzer should |
113 | // still warn when it can prove such errors. |
114 | int &y = *x; |
115 | if (x != 0) |
116 | return; |
117 | y = 5; // expected-warning{{Dereference of null pointer}} |
118 | } |
119 | |
120 | namespace TestReferenceAddress { |
121 | struct S { int &x; }; |
122 | S getS(); |
123 | S *getSP(); |
124 | |
125 | void testReferenceAddress(int &x) { |
126 | // FIXME: Move non-zero reference assumption out of RangeConstraintManager.cpp:422 |
127 | #ifdef ANALYZER_CM_Z3 |
128 | clang_analyzer_eval(&x != 0); // expected-warning{{UNKNOWN}} |
129 | clang_analyzer_eval(&ref() != 0); // expected-warning{{UNKNOWN}} |
130 | #else |
131 | clang_analyzer_eval(&x != 0); // expected-warning{{TRUE}} |
132 | clang_analyzer_eval(&ref() != 0); // expected-warning{{TRUE}} |
133 | #endif |
134 | |
135 | #ifdef ANALYZER_CM_Z3 |
136 | clang_analyzer_eval(&getS().x != 0); // expected-warning{{UNKNOWN}} |
137 | #else |
138 | clang_analyzer_eval(&getS().x != 0); // expected-warning{{TRUE}} |
139 | #endif |
140 | |
141 | #ifdef ANALYZER_CM_Z3 |
142 | clang_analyzer_eval(&getSP()->x != 0); // expected-warning{{UNKNOWN}} |
143 | #else |
144 | clang_analyzer_eval(&getSP()->x != 0); // expected-warning{{TRUE}} |
145 | #endif |
146 | } |
147 | } |
148 | |
149 | void testFunctionPointerReturn(void *opaque) { |
150 | typedef int &(*RefFn)(); |
151 | |
152 | RefFn getRef = (RefFn)opaque; |
153 | |
154 | // Don't crash writing to or reading from this reference. |
155 | int &x = getRef(); |
156 | x = 42; |
157 | clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} |
158 | } |
159 | |
160 | int &testReturnNullReference() { |
161 | int *x = 0; |
162 | return *x; // expected-warning{{Returning null reference}} |
163 | } |
164 | |
165 | char &refFromPointer() { |
166 | return *ptr(); |
167 | } |
168 | |
169 | void testReturnReference() { |
170 | clang_analyzer_eval(ptr() == 0); // expected-warning{{UNKNOWN}} |
171 | clang_analyzer_eval(&refFromPointer() == 0); // expected-warning{{FALSE}} |
172 | } |
173 | |
174 | void intRefParam(int &r) { |
175 | ; |
176 | } |
177 | |
178 | void test(int *ptr) { |
179 | clang_analyzer_eval(ptr == 0); // expected-warning{{UNKNOWN}} |
180 | |
181 | extern void use(int &ref); |
182 | use(*ptr); |
183 | |
184 | clang_analyzer_eval(ptr == 0); // expected-warning{{FALSE}} |
185 | } |
186 | |
187 | void testIntRefParam() { |
188 | int i = 0; |
189 | intRefParam(i); // no-warning |
190 | } |
191 | |
192 | int refParam(int &byteIndex) { |
193 | return byteIndex; |
194 | } |
195 | |
196 | void testRefParam(int *p) { |
197 | if (p) |
198 | ; |
199 | refParam(*p); // expected-warning {{Forming reference to null pointer}} |
200 | } |
201 | |
202 | int ptrRefParam(int *&byteIndex) { |
203 | return *byteIndex; // expected-warning {{Dereference of null pointer}} |
204 | } |
205 | void testRefParam2() { |
206 | int *p = 0; |
207 | int *&rp = p; |
208 | ptrRefParam(rp); |
209 | } |
210 | |
211 | int *maybeNull() { |
212 | extern bool coin(); |
213 | static int x; |
214 | return coin() ? &x : 0; |
215 | } |
216 | |
217 | void use(int &x) { |
218 | x = 1; // no-warning |
219 | } |
220 | |
221 | void testSuppression() { |
222 | use(*maybeNull()); |
223 | } |
224 | |
225 | namespace rdar11212286 { |
226 | class B{}; |
227 | |
228 | B test() { |
229 | B *x = 0; |
230 | return *x; // expected-warning {{Forming reference to null pointer}} |
231 | } |
232 | |
233 | B testif(B *x) { |
234 | if (x) |
235 | ; |
236 | return *x; // expected-warning {{Forming reference to null pointer}} |
237 | } |
238 | |
239 | void idc(B *x) { |
240 | if (x) |
241 | ; |
242 | } |
243 | |
244 | B testidc(B *x) { |
245 | idc(x); |
246 | return *x; // no-warning |
247 | } |
248 | } |
249 | |
250 | namespace PR15694 { |
251 | class C { |
252 | bool bit : 1; |
253 | template <class T> void bar(const T &obj) {} |
254 | void foo() { |
255 | bar(bit); // don't crash |
256 | } |
257 | }; |
258 | } |
259 | |