Ted Kremenek | cdc3a89 | 2012-08-24 20:39:55 +0000 | [diff] [blame] | 1 | // RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-constraints=range -verify %s |
Jordy Rose | 43d9f0d | 2012-05-16 16:01:10 +0000 | [diff] [blame] | 2 | |
| 3 | void clang_analyzer_eval(int); |
Jordy Rose | 23b736e | 2010-07-29 07:11:59 +0000 | [diff] [blame] | 4 | |
| 5 | int string_literal_init() { |
| 6 | char a[] = "abc"; |
| 7 | char b[2] = "abc"; // expected-warning{{too long}} |
| 8 | char c[5] = "abc"; |
| 9 | |
Jordy Rose | 43d9f0d | 2012-05-16 16:01:10 +0000 | [diff] [blame] | 10 | clang_analyzer_eval(a[1] == 'b'); // expected-warning{{TRUE}} |
| 11 | clang_analyzer_eval(b[1] == 'b'); // expected-warning{{TRUE}} |
| 12 | clang_analyzer_eval(c[1] == 'b'); // expected-warning{{TRUE}} |
Jordy Rose | 23b736e | 2010-07-29 07:11:59 +0000 | [diff] [blame] | 13 | |
Jordy Rose | 43d9f0d | 2012-05-16 16:01:10 +0000 | [diff] [blame] | 14 | clang_analyzer_eval(a[3] == 0); // expected-warning{{TRUE}} |
| 15 | clang_analyzer_eval(c[3] == 0); // expected-warning{{TRUE}} |
Jordy Rose | 23b736e | 2010-07-29 07:11:59 +0000 | [diff] [blame] | 16 | |
Jordy Rose | 43d9f0d | 2012-05-16 16:01:10 +0000 | [diff] [blame] | 17 | clang_analyzer_eval(c[4] == 0); // expected-warning{{TRUE}} |
Jordy Rose | 23b736e | 2010-07-29 07:11:59 +0000 | [diff] [blame] | 18 | |
| 19 | return 42; |
| 20 | } |
Jordy Rose | 59b6dca | 2010-08-20 01:05:59 +0000 | [diff] [blame] | 21 | |
| 22 | void nested_compound_literals(int rad) { |
David Blaikie | be0ee87 | 2012-05-15 16:56:36 +0000 | [diff] [blame] | 23 | int vec[6][2] = {{0.195, 0.02}, {0.383, 0.067}, {0.55, 0.169}, // expected-warning 6 {{implicit conversion from 'double' to 'int' changes value from}} |
| 24 | {0.831, 0.45}, {0.924, 0.617}, {0.98, 0.805}}; // expected-warning 6 {{implicit conversion from 'double' to 'int' changes value from}} |
Jordy Rose | 59b6dca | 2010-08-20 01:05:59 +0000 | [diff] [blame] | 25 | int a; |
| 26 | |
| 27 | for (a = 0; a < 6; ++a) { |
| 28 | vec[a][0] *= rad; // no-warning |
| 29 | vec[a][1] *= rad; // no-warning |
| 30 | } |
| 31 | } |
| 32 | |
| 33 | void nested_compound_literals_float(float rad) { |
| 34 | float vec[6][2] = {{0.195, 0.02}, {0.383, 0.067}, {0.55, 0.169}, |
| 35 | {0.831, 0.45}, {0.924, 0.617}, {0.98, 0.805}}; |
| 36 | int a; |
| 37 | |
| 38 | for (a = 0; a < 6; ++a) { |
| 39 | vec[a][0] *= rad; // no-warning |
| 40 | vec[a][1] *= rad; // no-warning |
| 41 | } |
| 42 | } |
Jordy Rose | f113940 | 2012-05-12 17:32:59 +0000 | [diff] [blame] | 43 | |
| 44 | |
| 45 | void struct_as_array() { |
Jordy Rose | 43d9f0d | 2012-05-16 16:01:10 +0000 | [diff] [blame] | 46 | struct simple { int x; int y; }; |
Jordy Rose | f113940 | 2012-05-12 17:32:59 +0000 | [diff] [blame] | 47 | struct simple a; |
| 48 | struct simple *p = &a; |
Jordy Rose | 43d9f0d | 2012-05-16 16:01:10 +0000 | [diff] [blame] | 49 | |
Jordy Rose | f113940 | 2012-05-12 17:32:59 +0000 | [diff] [blame] | 50 | p->x = 5; |
Jordy Rose | 43d9f0d | 2012-05-16 16:01:10 +0000 | [diff] [blame] | 51 | clang_analyzer_eval(a.x == 5); // expected-warning{{TRUE}} |
| 52 | clang_analyzer_eval(p[0].x == 5); // expected-warning{{TRUE}} |
| 53 | |
| 54 | p[0].y = 5; |
| 55 | clang_analyzer_eval(a.y == 5); // expected-warning{{TRUE}} |
| 56 | clang_analyzer_eval(p->y == 5); // expected-warning{{TRUE}} |
Jordy Rose | f113940 | 2012-05-12 17:32:59 +0000 | [diff] [blame] | 57 | } |
| 58 | |
Jordan Rose | 752bee2 | 2012-07-06 21:59:56 +0000 | [diff] [blame] | 59 | |
| 60 | // PR13264 / <rdar://problem/11802440> |
| 61 | struct point { int x; int y; }; |
| 62 | struct circle { struct point o; int r; }; |
| 63 | struct circle get_circle() { |
| 64 | struct circle result; |
| 65 | result.r = 5; |
| 66 | result.o = (struct point){0, 0}; |
| 67 | return result; |
| 68 | } |
| 69 | |
| 70 | void struct_in_struct() { |
| 71 | struct circle c; |
| 72 | c = get_circle(); |
| 73 | // This used to think c.r was undefined because c.o is a LazyCompoundVal. |
| 74 | clang_analyzer_eval(c.r == 5); // expected-warning{{TRUE}} |
| 75 | } |
| 76 | |
| 77 | // We also test with floats because we don't model floats right now, |
| 78 | // and the original bug report used a float. |
| 79 | struct circle_f { struct point o; float r; }; |
| 80 | struct circle_f get_circle_f() { |
| 81 | struct circle_f result; |
| 82 | result.r = 5.0; |
| 83 | result.o = (struct point){0, 0}; |
| 84 | return result; |
| 85 | } |
| 86 | |
| 87 | float struct_in_struct_f() { |
| 88 | struct circle_f c; |
| 89 | c = get_circle_f(); |
| 90 | |
| 91 | return c.r; // no-warning |
| 92 | } |
| 93 | |
Jordan Rose | e0d24eb | 2012-08-08 18:23:27 +0000 | [diff] [blame] | 94 | |
| 95 | int randomInt(); |
| 96 | |
| 97 | int testSymbolicInvalidation(int index) { |
| 98 | int vals[10]; |
| 99 | |
| 100 | vals[0] = 42; |
| 101 | clang_analyzer_eval(vals[0] == 42); // expected-warning{{TRUE}} |
| 102 | |
| 103 | vals[index] = randomInt(); |
| 104 | clang_analyzer_eval(vals[0] == 42); // expected-warning{{UNKNOWN}} |
| 105 | |
| 106 | return vals[index]; // no-warning |
| 107 | } |
| 108 | |
| 109 | int testConcreteInvalidation(int index) { |
| 110 | int vals[10]; |
| 111 | |
| 112 | vals[index] = 42; |
| 113 | clang_analyzer_eval(vals[index] == 42); // expected-warning{{TRUE}} |
| 114 | vals[0] = randomInt(); |
| 115 | clang_analyzer_eval(vals[index] == 42); // expected-warning{{UNKNOWN}} |
| 116 | |
| 117 | return vals[0]; // no-warning |
| 118 | } |
| 119 | |
| 120 | |
| 121 | typedef struct { |
| 122 | int x, y, z; |
| 123 | } S; |
| 124 | |
| 125 | S makeS(); |
| 126 | |
| 127 | int testSymbolicInvalidationStruct(int index) { |
| 128 | S vals[10]; |
| 129 | |
| 130 | vals[0].x = 42; |
| 131 | clang_analyzer_eval(vals[0].x == 42); // expected-warning{{TRUE}} |
| 132 | |
| 133 | vals[index] = makeS(); |
| 134 | clang_analyzer_eval(vals[0].x == 42); // expected-warning{{UNKNOWN}} |
| 135 | |
| 136 | return vals[index].x; // no-warning |
| 137 | } |
| 138 | |
| 139 | int testConcreteInvalidationStruct(int index) { |
| 140 | S vals[10]; |
| 141 | |
| 142 | vals[index].x = 42; |
| 143 | clang_analyzer_eval(vals[index].x == 42); // expected-warning{{TRUE}} |
| 144 | vals[0] = makeS(); |
| 145 | clang_analyzer_eval(vals[index].x == 42); // expected-warning{{UNKNOWN}} |
| 146 | |
| 147 | return vals[0].x; // no-warning |
| 148 | } |
| 149 | |
| 150 | typedef struct { |
| 151 | S a[5]; |
| 152 | S b[5]; |
| 153 | } SS; |
| 154 | |
| 155 | int testSymbolicInvalidationDoubleStruct(int index) { |
| 156 | SS vals; |
| 157 | |
| 158 | vals.a[0].x = 42; |
| 159 | vals.b[0].x = 42; |
| 160 | clang_analyzer_eval(vals.a[0].x == 42); // expected-warning{{TRUE}} |
| 161 | clang_analyzer_eval(vals.b[0].x == 42); // expected-warning{{TRUE}} |
| 162 | |
| 163 | vals.a[index] = makeS(); |
| 164 | clang_analyzer_eval(vals.a[0].x == 42); // expected-warning{{UNKNOWN}} |
| 165 | clang_analyzer_eval(vals.b[0].x == 42); // expected-warning{{TRUE}} |
| 166 | |
| 167 | return vals.b[index].x; // no-warning |
| 168 | } |
| 169 | |
| 170 | int testConcreteInvalidationDoubleStruct(int index) { |
| 171 | SS vals; |
| 172 | |
| 173 | vals.a[index].x = 42; |
| 174 | vals.b[index].x = 42; |
| 175 | clang_analyzer_eval(vals.a[index].x == 42); // expected-warning{{TRUE}} |
| 176 | clang_analyzer_eval(vals.b[index].x == 42); // expected-warning{{TRUE}} |
| 177 | |
| 178 | vals.a[0] = makeS(); |
| 179 | clang_analyzer_eval(vals.a[index].x == 42); // expected-warning{{UNKNOWN}} |
| 180 | clang_analyzer_eval(vals.b[index].x == 42); // expected-warning{{TRUE}} |
| 181 | |
| 182 | return vals.b[0].x; // no-warning |
| 183 | } |
| 184 | |
| 185 | |
Jordan Rose | 4e674f7 | 2012-11-10 01:40:08 +0000 | [diff] [blame] | 186 | int testNonOverlappingStructFieldsSimple() { |
| 187 | S val; |
| 188 | |
| 189 | val.x = 1; |
| 190 | val.y = 2; |
| 191 | clang_analyzer_eval(val.x == 1); // expected-warning{{TRUE}} |
| 192 | clang_analyzer_eval(val.y == 2); // expected-warning{{TRUE}} |
| 193 | |
| 194 | return val.z; // expected-warning{{garbage}} |
| 195 | } |
| 196 | |
| 197 | int testNonOverlappingStructFieldsSymbolicBase(int index, int anotherIndex) { |
| 198 | SS vals; |
| 199 | |
| 200 | vals.a[index].x = 42; |
| 201 | vals.a[index].y = 42; |
| 202 | clang_analyzer_eval(vals.a[index].x == 42); // expected-warning{{TRUE}} |
| 203 | clang_analyzer_eval(vals.a[index].y == 42); // expected-warning{{TRUE}} |
| 204 | |
| 205 | vals.a[anotherIndex].x = 42; |
| 206 | clang_analyzer_eval(vals.a[index].x == 42); // expected-warning{{UNKNOWN}} |
| 207 | clang_analyzer_eval(vals.a[index].y == 42); // expected-warning{{TRUE}} |
| 208 | |
| 209 | // FIXME: False negative. No bind ever set a field 'z'. |
| 210 | return vals.a[index].z; // no-warning |
| 211 | } |
| 212 | |
| 213 | int testStructFieldChains(int index, int anotherIndex) { |
| 214 | SS vals[4]; |
| 215 | |
| 216 | vals[index].a[0].x = 42; |
| 217 | vals[anotherIndex].a[1].y = 42; |
| 218 | clang_analyzer_eval(vals[index].a[0].x == 42); // expected-warning{{TRUE}} |
| 219 | clang_analyzer_eval(vals[anotherIndex].a[1].y == 42); // expected-warning{{TRUE}} |
| 220 | |
| 221 | // This doesn't affect anything in the 'a' array field. |
| 222 | vals[anotherIndex].b[1].x = 42; |
| 223 | clang_analyzer_eval(vals[index].a[0].x == 42); // expected-warning{{TRUE}} |
| 224 | clang_analyzer_eval(vals[anotherIndex].a[1].y == 42); // expected-warning{{TRUE}} |
| 225 | clang_analyzer_eval(vals[anotherIndex].b[1].x == 42); // expected-warning{{TRUE}} |
| 226 | |
| 227 | // This doesn't affect anything in the 'b' array field. |
| 228 | vals[index].a[anotherIndex].x = 42; |
| 229 | clang_analyzer_eval(vals[index].a[0].x == 42); // expected-warning{{UNKNOWN}} |
| 230 | clang_analyzer_eval(vals[anotherIndex].a[0].x == 42); // expected-warning{{UNKNOWN}} |
| 231 | clang_analyzer_eval(vals[anotherIndex].a[1].y == 42); // expected-warning{{TRUE}} |
| 232 | clang_analyzer_eval(vals[anotherIndex].b[1].x == 42); // expected-warning{{TRUE}} |
| 233 | |
| 234 | // FIXME: False negative. No bind ever set a field 'z'. |
| 235 | return vals[index].a[0].z; // no-warning |
| 236 | } |
| 237 | |
| 238 | int testStructFieldChainsNested(int index, int anotherIndex) { |
| 239 | SS vals[4]; |
| 240 | |
| 241 | vals[index].a[0].x = 42; |
| 242 | clang_analyzer_eval(vals[index].a[0].x == 42); // expected-warning{{TRUE}} |
| 243 | |
| 244 | vals[index].b[0] = makeS(); |
| 245 | clang_analyzer_eval(vals[index].a[0].x == 42); // expected-warning{{TRUE}} |
| 246 | |
| 247 | vals[index].a[0] = makeS(); |
| 248 | clang_analyzer_eval(vals[index].a[0].x == 42); // expected-warning{{UNKNOWN}} |
| 249 | |
| 250 | vals[index].a[0].x = 42; |
| 251 | clang_analyzer_eval(vals[index].a[0].x == 42); // expected-warning{{TRUE}} |
| 252 | |
| 253 | return 0; |
| 254 | } |
| 255 | |
Anna Zaks | 5255f27 | 2013-01-31 01:19:52 +0000 | [diff] [blame] | 256 | typedef struct { |
| 257 | int zoomLevel; |
| 258 | struct point center; |
| 259 | } Outer; |
| 260 | |
| 261 | extern int test13116945(struct point x); |
| 262 | static void radar13116945(struct point centerCoordinate) { |
| 263 | Outer zoomRegion; |
| 264 | zoomRegion.zoomLevel = 0; |
| 265 | zoomRegion.center = centerCoordinate; |
| 266 | Outer r = zoomRegion; |
| 267 | test13116945(r.center); // no-warning |
| 268 | } |
Jordan Rose | 4e674f7 | 2012-11-10 01:40:08 +0000 | [diff] [blame] | 269 | |
Jordan Rose | 978aeac | 2013-02-01 19:49:57 +0000 | [diff] [blame] | 270 | |
| 271 | typedef struct { |
| 272 | char data[4]; |
| 273 | } ShortString; |
| 274 | |
| 275 | typedef struct { |
| 276 | ShortString str; |
| 277 | int length; |
| 278 | } ShortStringWrapper; |
| 279 | |
| 280 | void testArrayStructCopy() { |
| 281 | ShortString s = { "abc" }; |
| 282 | ShortString s2 = s; |
| 283 | ShortString s3 = s2; |
| 284 | |
| 285 | clang_analyzer_eval(s3.data[0] == 'a'); // expected-warning{{TRUE}} |
| 286 | clang_analyzer_eval(s3.data[1] == 'b'); // expected-warning{{TRUE}} |
| 287 | clang_analyzer_eval(s3.data[2] == 'c'); // expected-warning{{TRUE}} |
Jordan Rose | 11f0cae | 2013-02-21 01:34:51 +0000 | [diff] [blame] | 288 | |
| 289 | s3.data[0] = 'z'; |
| 290 | ShortString s4 = s3; |
| 291 | |
| 292 | clang_analyzer_eval(s4.data[0] == 'z'); // expected-warning{{TRUE}} |
| 293 | clang_analyzer_eval(s4.data[1] == 'b'); // expected-warning{{TRUE}} |
| 294 | clang_analyzer_eval(s4.data[2] == 'c'); // expected-warning{{TRUE}} |
Jordan Rose | 978aeac | 2013-02-01 19:49:57 +0000 | [diff] [blame] | 295 | } |
| 296 | |
| 297 | void testArrayStructCopyNested() { |
| 298 | ShortString s = { "abc" }; |
| 299 | ShortString s2 = s; |
| 300 | |
| 301 | ShortStringWrapper w = { s2, 0 }; |
| 302 | |
| 303 | clang_analyzer_eval(w.str.data[0] == 'a'); // expected-warning{{TRUE}} |
| 304 | clang_analyzer_eval(w.str.data[1] == 'b'); // expected-warning{{TRUE}} |
| 305 | clang_analyzer_eval(w.str.data[2] == 'c'); // expected-warning{{TRUE}} |
| 306 | clang_analyzer_eval(w.length == 0); // expected-warning{{TRUE}} |
| 307 | |
| 308 | ShortStringWrapper w2 = w; |
| 309 | clang_analyzer_eval(w2.str.data[0] == 'a'); // expected-warning{{TRUE}} |
| 310 | clang_analyzer_eval(w2.str.data[1] == 'b'); // expected-warning{{TRUE}} |
| 311 | clang_analyzer_eval(w2.str.data[2] == 'c'); // expected-warning{{TRUE}} |
| 312 | clang_analyzer_eval(w2.length == 0); // expected-warning{{TRUE}} |
| 313 | |
| 314 | ShortStringWrapper w3 = w2; |
| 315 | clang_analyzer_eval(w3.str.data[0] == 'a'); // expected-warning{{TRUE}} |
| 316 | clang_analyzer_eval(w3.str.data[1] == 'b'); // expected-warning{{TRUE}} |
| 317 | clang_analyzer_eval(w3.str.data[2] == 'c'); // expected-warning{{TRUE}} |
| 318 | clang_analyzer_eval(w3.length == 0); // expected-warning{{TRUE}} |
| 319 | } |
| 320 | |
Jordan Rose | 4e674f7 | 2012-11-10 01:40:08 +0000 | [diff] [blame] | 321 | // -------------------- |
| 322 | // False positives |
| 323 | // -------------------- |
| 324 | |
| 325 | int testMixSymbolicAndConcrete(int index, int anotherIndex) { |
| 326 | SS vals; |
| 327 | |
| 328 | vals.a[index].x = 42; |
| 329 | vals.a[0].y = 42; |
| 330 | |
| 331 | // FIXME: Should be TRUE. |
| 332 | clang_analyzer_eval(vals.a[index].x == 42); // expected-warning{{UNKNOWN}} |
| 333 | // Should be TRUE; we set this explicitly. |
| 334 | clang_analyzer_eval(vals.a[0].y == 42); // expected-warning{{TRUE}} |
| 335 | |
| 336 | vals.a[anotherIndex].y = 42; |
| 337 | |
| 338 | // Should be UNKNOWN; we set an 'x'. |
| 339 | clang_analyzer_eval(vals.a[index].x == 42); // expected-warning{{UNKNOWN}} |
| 340 | // FIXME: Should be TRUE. |
| 341 | clang_analyzer_eval(vals.a[0].y == 42); // expected-warning{{UNKNOWN}} |
| 342 | |
| 343 | return vals.a[0].x; // no-warning |
| 344 | } |
| 345 | |
| 346 | void testFieldChainIsNotEnough(int index) { |
| 347 | SS vals[4]; |
| 348 | |
| 349 | vals[index].a[0].x = 42; |
| 350 | clang_analyzer_eval(vals[index].a[0].x == 42); // expected-warning{{TRUE}} |
| 351 | |
| 352 | vals[index].a[1] = makeS(); |
| 353 | // FIXME: Should be TRUE. |
| 354 | clang_analyzer_eval(vals[index].a[0].x == 42); // expected-warning{{UNKNOWN}} |
| 355 | } |