1 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify -analyzer-config eagerly-assume=false %s 2 3 template <class T> void clang_analyzer_dump(T); 4 void clang_analyzer_eval(bool); 5 6 void usePointer(int * const *); 7 void useReference(int * const &); 8 9 void testPointer() { 10 int x; 11 int *p; 12 13 p = &x; 14 x = 42; 15 clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} 16 usePointer(&p); 17 clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}} 18 19 p = &x; 20 x = 42; 21 clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} 22 useReference(p); 23 clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}} 24 25 int * const cp1 = &x; 26 x = 42; 27 clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} 28 usePointer(&cp1); 29 clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}} 30 31 int * const cp2 = &x; 32 x = 42; 33 clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} 34 useReference(cp2); 35 clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}} 36 } 37 38 39 struct Wrapper { 40 int *ptr; 41 }; 42 43 void useStruct(Wrapper &w); 44 void useConstStruct(const Wrapper &w); 45 46 void testPointerStruct() { 47 int x; 48 Wrapper w; 49 50 w.ptr = &x; 51 x = 42; 52 clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} 53 useStruct(w); 54 clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}} 55 56 w.ptr = &x; 57 x = 42; 58 clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} 59 useConstStruct(w); 60 clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}} 61 } 62 63 64 struct RefWrapper { 65 int &ref; 66 }; 67 68 void useStruct(RefWrapper &w); 69 void useConstStruct(const RefWrapper &w); 70 71 void testReferenceStruct() { 72 int x; 73 RefWrapper w = { x }; 74 75 x = 42; 76 clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} 77 useStruct(w); 78 clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}} 79 } 80 81 // FIXME: This test is split into two functions because region invalidation 82 // does not preserve reference bindings. 83 void testConstReferenceStruct() { 84 int x; 85 RefWrapper w = { x }; 86 87 x = 42; 88 clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} 89 useConstStruct(w); 90 clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}} 91 } 92 93 94 int usePointerPure(int * const *) __attribute__((pure)); 95 int usePointerConst(int * const *) __attribute__((const)); 96 97 void testPureConst() { 98 extern int global; 99 int x; 100 int *p; 101 102 p = &x; 103 x = 42; 104 global = -5; 105 clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} 106 clang_analyzer_eval(global == -5); // expected-warning{{TRUE}} 107 108 (void)usePointerPure(&p); 109 clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} 110 clang_analyzer_eval(global == -5); // expected-warning{{TRUE}} 111 112 (void)usePointerConst(&p); 113 clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} 114 clang_analyzer_eval(global == -5); // expected-warning{{TRUE}} 115 116 usePointer(&p); 117 clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}} 118 clang_analyzer_eval(global == -5); // expected-warning{{UNKNOWN}} 119 } 120 121 122 struct PlainStruct { 123 int x, y; 124 mutable int z; 125 }; 126 127 PlainStruct glob; 128 129 void useAnything(void *); 130 void useAnythingConst(const void *); 131 132 void testInvalidationThroughBaseRegionPointer() { 133 PlainStruct s1; 134 s1.x = 1; 135 s1.z = 1; 136 clang_analyzer_eval(s1.x == 1); // expected-warning{{TRUE}} 137 clang_analyzer_eval(s1.z == 1); // expected-warning{{TRUE}} 138 // Not only passing a structure pointer through const pointer parameter, 139 // but also passing a field pointer through const pointer parameter 140 // should preserve the contents of the structure. 141 useAnythingConst(&(s1.y)); 142 clang_analyzer_eval(s1.x == 1); // expected-warning{{TRUE}} 143 // FIXME: Should say "UNKNOWN", because it is not uncommon to 144 // modify a mutable member variable through const pointer. 145 clang_analyzer_eval(s1.z == 1); // expected-warning{{TRUE}} 146 useAnything(&(s1.y)); 147 clang_analyzer_eval(s1.x == 1); // expected-warning{{UNKNOWN}} 148 } 149 150 151 void useFirstConstSecondNonConst(const void *x, void *y); 152 void useFirstNonConstSecondConst(void *x, const void *y); 153 154 void testMixedConstNonConstCalls() { 155 PlainStruct s2; 156 s2.x = 1; 157 useFirstConstSecondNonConst(&(s2.x), &(s2.y)); 158 clang_analyzer_eval(s2.x == 1); // expected-warning{{UNKNOWN}} 159 s2.x = 1; 160 useFirstNonConstSecondConst(&(s2.x), &(s2.y)); 161 clang_analyzer_eval(s2.x == 1); // expected-warning{{UNKNOWN}} 162 s2.y = 1; 163 useFirstConstSecondNonConst(&(s2.x), &(s2.y)); 164 clang_analyzer_eval(s2.y == 1); // expected-warning{{UNKNOWN}} 165 s2.y = 1; 166 useFirstNonConstSecondConst(&(s2.x), &(s2.y)); 167 clang_analyzer_eval(s2.y == 1); // expected-warning{{UNKNOWN}} 168 } 169 170 namespace std { 171 class Opaque { 172 public: 173 Opaque(); 174 int nested_member; 175 }; 176 } // namespace std 177 178 struct StdWrappingOpaque { 179 std::Opaque o; // first member 180 int uninit; 181 }; 182 struct StdWrappingOpaqueSwapped { 183 int uninit; // first member 184 std::Opaque o; 185 }; 186 187 int testStdCtorDoesNotInvalidateParentObject() { 188 StdWrappingOpaque obj; 189 int x = obj.o.nested_member; // no-garbage: std::Opaque::ctor might initialized this 190 int y = obj.uninit; // FIXME: We should have a garbage read here. Read the details. 191 // As the first member ("obj.o") is invalidated, a conjured default binding is bound 192 // to the offset 0 within cluster "obj", and this masks every uninitialized fields 193 // that follows. We need a better store with extents to fix this. 194 return x + y; 195 } 196 197 int testStdCtorDoesNotInvalidateParentObjectSwapped() { 198 StdWrappingOpaqueSwapped obj; 199 int x = obj.o.nested_member; // no-garbage: std::Opaque::ctor might initialized this 200 int y = obj.uninit; // expected-warning {{Assigned value is garbage or undefined}} 201 return x + y; 202 } 203 204 class UserProvidedOpaque { 205 public: 206 UserProvidedOpaque(); // might reinterpret_cast(this) 207 int nested_member; 208 }; 209 210 struct WrappingUserProvidedOpaque { 211 UserProvidedOpaque o; // first member 212 int uninit; 213 }; 214 struct WrappingUserProvidedOpaqueSwapped { 215 int uninit; // first member 216 UserProvidedOpaque o; 217 }; 218 219 int testUserProvidedCtorInvalidatesParentObject() { 220 WrappingUserProvidedOpaque obj; 221 int x = obj.o.nested_member; // no-garbage: UserProvidedOpaque::ctor might initialized this 222 int y = obj.uninit; // no-garbage: UserProvidedOpaque::ctor might reinterpret_cast(this) and write to the "uninit" member. 223 return x + y; 224 } 225 226 int testUserProvidedCtorInvalidatesParentObjectSwapped() { 227 WrappingUserProvidedOpaqueSwapped obj; 228 int x = obj.o.nested_member; // no-garbage: same as above 229 int y = obj.uninit; // no-garbage: same as above 230 return x + y; 231 } 232 233 struct WrappingStdWrappingOpaqueOuterInits { 234 int first = 1; 235 std::Opaque second; 236 int third = 3; 237 WrappingStdWrappingOpaqueOuterInits() { 238 clang_analyzer_dump(first); // expected-warning {{1 S32b}} 239 clang_analyzer_dump(second.nested_member); // expected-warning {{derived_}} 240 clang_analyzer_dump(third); // expected-warning {{3 S32b}} 241 } 242 }; 243 244 struct WrappingUserProvidedOpaqueOuterInits { 245 int first = 1; // Potentially overwritten by UserProvidedOpaque::ctor 246 UserProvidedOpaque second; // Invalidates the object so far. 247 int third = 3; // Happens after UserProvidedOpaque::ctor, thus preserved! 248 WrappingUserProvidedOpaqueOuterInits() { 249 clang_analyzer_dump(first); // expected-warning {{derived_}} 250 clang_analyzer_dump(second.nested_member); // expected-warning {{derived_}} 251 clang_analyzer_dump(third); // expected-warning {{3 S32b}} 252 } 253 }; 254 255 extern "C++" { 256 namespace std { 257 inline namespace v1 { 258 namespace custom_ranges { 259 struct Fancy { 260 struct iterator { 261 struct Opaque { 262 Opaque(); 263 int nested_member; 264 }; // struct Opaque 265 }; // struct iterator 266 }; // struct Fancy 267 } // namespace custom_ranges 268 } // namespace v1 269 } // namespace std 270 } // extern "C++" 271 272 struct StdWrappingFancyOpaque { 273 int uninit; 274 std::custom_ranges::Fancy::iterator::Opaque o; 275 }; 276 277 int testNestedStdNamespacesAndRecords() { 278 StdWrappingFancyOpaque obj; 279 int x = obj.o.nested_member; // no-garbage: ctor 280 int y = obj.uninit; // expected-warning {{Assigned value is garbage or undefined}} 281 return x + y; 282 } 283