reference.cpp revision a34d4f47321324187ed57948628f5938357ae034
1// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core,debug.ExprInspection -analyzer-store=region -analyzer-constraints=basic -verify -Wno-null-dereference %s 2// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core,debug.ExprInspection -analyzer-store=region -analyzer-constraints=range -verify -Wno-null-dereference %s 3 4void clang_analyzer_eval(bool); 5 6typedef typeof(sizeof(int)) size_t; 7void malloc (size_t); 8 9void f1() { 10 int const &i = 3; 11 int b = i; 12 13 int *p = 0; 14 15 if (b != 3) 16 *p = 1; // no-warning 17} 18 19char* ptr(); 20char& ref(); 21 22// These next two tests just shouldn't crash. 23char t1 () { 24 ref() = 'c'; 25 return '0'; 26} 27 28// just a sanity test, the same behavior as t1() 29char t2 () { 30 *ptr() = 'c'; 31 return '0'; 32} 33 34// Each of the tests below is repeated with pointers as well as references. 35// This is mostly a sanity check, but then again, both should work! 36char t3 () { 37 char& r = ref(); 38 r = 'c'; // no-warning 39 if (r) return r; 40 return *(char*)0; // no-warning 41} 42 43char t4 () { 44 char* p = ptr(); 45 *p = 'c'; // no-warning 46 if (*p) return *p; 47 return *(char*)0; // no-warning 48} 49 50char t5 (char& r) { 51 r = 'c'; // no-warning 52 if (r) return r; 53 return *(char*)0; // no-warning 54} 55 56char t6 (char* p) { 57 *p = 'c'; // no-warning 58 if (*p) return *p; 59 return *(char*)0; // no-warning 60} 61 62 63// PR13440 / <rdar://problem/11977113> 64// Test that the array-to-pointer decay works for array references as well. 65// More generally, when we want an lvalue for a reference field, we still need 66// to do one level of load. 67namespace PR13440 { 68 typedef int T[1]; 69 struct S { 70 T &x; 71 72 int *m() { return x; } 73 }; 74 75 struct S2 { 76 int (&x)[1]; 77 78 int *m() { return x; } 79 }; 80 81 void test() { 82 int a[1]; 83 S s = { a }; 84 S2 s2 = { a }; 85 86 if (s.x != a) return; 87 if (s2.x != a) return; 88 89 a[0] = 42; 90 clang_analyzer_eval(s.x[0] == 42); // expected-warning{{TRUE}} 91 clang_analyzer_eval(s2.x[0] == 42); // expected-warning{{TRUE}} 92 } 93} 94 95void testNullReference() { 96 int *x = 0; 97 int &y = *x; // expected-warning{{Dereference of null pointer}} 98 y = 5; 99} 100 101void testRetroactiveNullReference(int *x) { 102 // According to the C++ standard, there is no such thing as a 103 // "null reference". So the 'if' statement ought to be dead code. 104 // However, Clang (and other compilers) don't actually check that a pointer 105 // value is non-null in the implementation of references, so it is possible 106 // to produce a supposed "null reference" at runtime. The analyzer shoeuld 107 // still warn when it can prove such errors. 108 int &y = *x; 109 if (x != 0) 110 return; 111 y = 5; // expected-warning{{Dereference of null pointer}} 112} 113 114void testReferenceAddress(int &x) { 115 clang_analyzer_eval(&x != 0); // expected-warning{{TRUE}} 116 clang_analyzer_eval(&ref() != 0); // expected-warning{{TRUE}} 117 118 struct S { int &x; }; 119 120 extern S *getS(); 121 clang_analyzer_eval(&getS()->x != 0); // expected-warning{{TRUE}} 122} 123 124 125// ------------------------------------ 126// False negatives 127// ------------------------------------ 128 129namespace rdar11212286 { 130 class B{}; 131 132 B test() { 133 B *x = 0; 134 return *x; // should warn here! 135 } 136 137 B &testRef() { 138 B *x = 0; 139 return *x; // should warn here! 140 } 141} 142 143void testReferenceFieldAddress() { 144 struct S { int &x; }; 145 146 extern S getS(); 147 clang_analyzer_eval(&getS().x != 0); // expected-warning{{UNKNOWN}} 148} 149