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