diff options
Diffstat (limited to 'clang/test/Analysis/pr22954.c')
| -rw-r--r-- | clang/test/Analysis/pr22954.c | 916 |
1 files changed, 916 insertions, 0 deletions
diff --git a/clang/test/Analysis/pr22954.c b/clang/test/Analysis/pr22954.c new file mode 100644 index 00000000000..01aa5b34a7e --- /dev/null +++ b/clang/test/Analysis/pr22954.c @@ -0,0 +1,916 @@ +// Given code 'struct aa { char s1[4]; char * s2;} a; memcpy(a.s1, ...);', +// this test checks that the CStringChecker only invalidates the destination buffer array a.s1 (instead of a.s1 and a.s2). +// At the moment the whole of the destination array content is invalidated. +// If a.s1 region has a symbolic offset, the whole region of 'a' is invalidated. +// Specific triple set to test structures of size 0. +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-store=region -verify %s + +typedef __typeof(sizeof(int)) size_t; + +char *strdup(const char *s); +void free(void *); +void *memcpy(void *dst, const void *src, size_t n); // expected-note{{passing argument to parameter 'dst' here}} +void *malloc(size_t n); + +void clang_analyzer_eval(int); + +struct aa { + char s1[4]; + char *s2; +}; + +// Test different types of structure initialisation. +int f0() { + struct aa a0 = {{1, 2, 3, 4}, 0}; + a0.s2 = strdup("hello"); + char input[] = {'a', 'b', 'c', 'd'}; + memcpy(a0.s1, input, 4); + clang_analyzer_eval(a0.s1[0] == 'a'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a0.s1[1] == 'b'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a0.s1[2] == 'c'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a0.s1[3] == 'd'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a0.s2 == 0); // expected-warning{{UNKNOWN}} + free(a0.s2); // no warning + return 0; +} + +int f1() { + struct aa a1; + a1.s2 = strdup("hello"); + char input[] = {'a', 'b', 'c', 'd'}; + memcpy(a1.s1, input, 4); + clang_analyzer_eval(a1.s1[0] == 'a'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a1.s1[1] == 'b'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a1.s1[2] == 'c'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a1.s1[3] == 'd'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a1.s2 == 0); // expected-warning{{UNKNOWN}} + free(a1.s2); // no warning + return 0; +} + +int f2() { + struct aa a2 = {{1, 2}}; + a2.s2 = strdup("hello"); + char input[] = {'a', 'b', 'c', 'd'}; + memcpy(a2.s1, input, 4); + clang_analyzer_eval(a2.s1[0] == 'a'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a2.s1[1] == 'b'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a2.s1[2] == 'c'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a2.s1[3] == 'd'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a2.s2 == 0); // expected-warning{{UNKNOWN}} + free(a2.s2); // no warning + return 0; +} + +int f3() { + struct aa a3 = {{1, 2, 3, 4}, 0}; + a3.s2 = strdup("hello"); + char input[] = {'a', 'b', 'c', 'd'}; + int * dest = (int*)a3.s1; + memcpy(dest, input, 4); + clang_analyzer_eval(a3.s1[0] == 'a'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(dest[0] == 'a'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a3.s1[1] == 'b'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(dest[1] == 'b'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a3.s1[2] == 'c'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(dest[2] == 'c'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a3.s1[3] == 'd'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(dest[3] == 'd'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a3.s2 == 0); // expected-warning{{UNKNOWN}} + free(a3.s2); // no warning + return 0; +} + +struct bb { + struct aa a; + char * s2; +}; + +int f4() { + struct bb b0 = {{1, 2, 3, 4}, 0}; + b0.s2 = strdup("hello"); + b0.a.s2 = strdup("hola"); + char input[] = {'a', 'b', 'c', 'd'}; + char * dest = (char*)(b0.a.s1); + memcpy(dest, input, 4); + clang_analyzer_eval(b0.a.s1[0] == 'a'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(dest[0] == 'a'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(b0.a.s1[1] == 'b'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(dest[1] == 'b'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(b0.a.s1[2] == 'c'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(dest[2] == 'c'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(b0.a.s1[3] == 'd'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(dest[3] == 'd'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(b0.s2 == 0); // expected-warning{{UNKNOWN}} + free(b0.a.s2); // no warning + free(b0.s2); // no warning + return 0; +} + +// Test that memory leaks are caught. +int f5() { + struct aa a0 = {{1, 2, 3, 4}, 0}; + a0.s2 = strdup("hello"); + char input[] = {'a', 'b', 'c', 'd'}; + memcpy(a0.s1, input, 4); + return 0; // expected-warning{{Potential leak of memory pointed to by 'a0.s2'}} +} + +int f6() { + struct aa a1; + a1.s2 = strdup("hello"); + char input[] = {'a', 'b', 'c', 'd'}; + memcpy(a1.s1, input, 4); + return 0; // expected-warning{{Potential leak of memory pointed to by 'a1.s2'}} +} + +int f7() { + struct aa a2 = {{1, 2}}; + a2.s2 = strdup("hello"); + char input[] = {'a', 'b', 'c', 'd'}; + memcpy(a2.s1, input, 4); + return 0; // expected-warning{{Potential leak of memory pointed to by 'a2.s2'}} +} + +int f8() { + struct aa a3 = {{1, 2, 3, 4}, 0}; + a3.s2 = strdup("hello"); + char input[] = {'a', 'b', 'c', 'd'}; + int * dest = (int*)a3.s1; + memcpy(dest, input, 4); + return 0; // expected-warning{{Potential leak of memory pointed to by 'a3.s2'}} +} + +int f9() { + struct bb b0 = {{1, 2, 3, 4}, 0}; + b0.s2 = strdup("hello"); + b0.a.s2 = strdup("hola"); + char input[] = {'a', 'b', 'c', 'd'}; + char * dest = (char*)(b0.a.s1); + memcpy(dest, input, 4); + free(b0.a.s2); // expected-warning{{Potential leak of memory pointed to by 'b0.s2'}} + return 0; +} + +int f10() { + struct bb b0 = {{1, 2, 3, 4}, 0}; + b0.s2 = strdup("hello"); + b0.a.s2 = strdup("hola"); + char input[] = {'a', 'b', 'c', 'd'}; + char * dest = (char*)(b0.a.s1); + memcpy(dest, input, 4); + free(b0.s2); // expected-warning{{Potential leak of memory pointed to by 'b0.a.s2'}} + return 0; +} + +// Test invalidating fields being addresses of array. +struct cc { + char * s1; + char * s2; +}; + +int f11() { + char x[4] = {1, 2}; + x[0] = 1; + x[1] = 2; + struct cc c0; + c0.s2 = strdup("hello"); + c0.s1 = &x[0]; + char input[] = {'a', 'b', 'c', 'd'}; + memcpy(c0.s1, input, 4); + clang_analyzer_eval(x[0] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(x[1] == 2); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(c0.s1[0] == 'a'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(c0.s1[1] == 'b'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(c0.s1[2] == 'c'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(c0.s1[3] == 'd'); // expected-warning{{UNKNOWN}} + free(c0.s2); // no-warning + return 0; +} + +// Test inverting field position between s1 and s2. +struct dd { + char *s2; + char s1[4]; +}; + +int f12() { + struct dd d0 = {0, {1, 2, 3, 4}}; + d0.s2 = strdup("hello"); + char input[] = {'a', 'b', 'c', 'd'}; + memcpy(d0.s1, input, 4); + clang_analyzer_eval(d0.s1[0] == 'a'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(d0.s1[1] == 'b'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(d0.s1[2] == 'c'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(d0.s1[3] == 'd'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(d0.s2 == 0); // expected-warning{{UNKNOWN}} + free(d0.s2); // no warning + return 0; +} + +// Test arrays of structs. +struct ee { + int a; + char b; +}; + +struct EE { + struct ee s1[2]; + char * s2; +}; + +int f13() { + struct EE E0 = {{{1, 2}, {3, 4}}, 0}; + E0.s2 = strdup("hello"); + char input[] = {'a', 'b', 'c', 'd'}; + memcpy(E0.s1, input, 4); + clang_analyzer_eval(E0.s1[0].a == 'a'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(E0.s1[0].b == 'b'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(E0.s1[1].a == 'c'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(E0.s1[1].b == 'd'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(E0.s2 == 0); // expected-warning{{UNKNOWN}} + free(E0.s2); // no warning + return 0; +} + +// Test global parameters. +struct aa a15 = {{1, 2, 3, 4}, 0}; + +int f15() { + a15.s2 = strdup("hello"); + char input[] = {'a', 'b', 'c', 'd'}; + memcpy(a15.s1, input, 4); + clang_analyzer_eval(a15.s1[0] == 'a'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a15.s1[1] == 'b'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a15.s1[2] == 'c'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a15.s1[3] == 'd'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a15.s2 == 0); // expected-warning{{UNKNOWN}} + free(a15.s2); // no warning + return 0; +} + +// Test array of 0 sized elements. +struct empty {}; +struct gg { + struct empty s1[4]; + char * s2; +}; + +int f16() { + struct gg g0 = {{}, 0}; + g0.s2 = strdup("hello"); + char input[] = {'a', 'b', 'c', 'd'}; + memcpy(g0.s1, input, 4); + clang_analyzer_eval(*(int*)(&g0.s1[0]) == 'a'); // expected-warning{{UNKNOWN}}\ + expected-warning{{Potential leak of memory pointed to by 'g0.s2'}} + clang_analyzer_eval(*(int*)(&g0.s1[1]) == 'b'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(*(int*)(&g0.s1[2]) == 'c'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(*(int*)(&g0.s1[3]) == 'd'); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(g0.s2 == 0); // expected-warning{{UNKNOWN}} + free(g0.s2); // no warning + return 0; +} + +// Test array of 0 elements. +struct hh { + char s1[0]; + char * s2; +}; + +int f17() { + struct hh h0; + h0.s2 = strdup("hello"); + char input[] = {'a', 'b', 'c', 'd'}; + memcpy(h0.s1, input, 4); + clang_analyzer_eval(h0.s1[0] == 'a'); // expected-warning{{UNKNOWN}}\ + expected-warning{{Potential leak of memory pointed to by 'h0.s2'}} + clang_analyzer_eval(h0.s2 == 0); // expected-warning{{UNKNOWN}} + free(h0.s2); // no warning + return 0; +} + +// Test writing past the array. +struct ii { + char s1[4]; + int i; + int j; + char * s2; +}; + +int f18() { + struct ii i18 = {{1, 2, 3, 4}, 5, 6}; + i18.i = 10; + i18.j = 11; + i18.s2 = strdup("hello"); + char input[100] = {3}; + memcpy(i18.s1, input, 100); + clang_analyzer_eval(i18.s1[0] == 1); // expected-warning{{UNKNOWN}}\ + expected-warning{{Potential leak of memory pointed to by 'i18.s2'}} + clang_analyzer_eval(i18.s1[1] == 2); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(i18.s1[2] == 3); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(i18.s1[3] == 4); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(i18.i == 10); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(i18.j == 11); // expected-warning{{UNKNOWN}} + return 0; +} + +int f181() { + struct ii i181 = {{1, 2, 3, 4}, 5, 6}; + i181.i = 10; + i181.j = 11; + i181.s2 = strdup("hello"); + char input[100] = {3}; + memcpy(i181.s1, input, 5); // invalidate the whole region of i181 + clang_analyzer_eval(i181.s1[0] == 1); // expected-warning{{UNKNOWN}}\ + expected-warning{{Potential leak of memory pointed to by 'i181.s2'}} + clang_analyzer_eval(i181.s1[1] == 2); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(i181.s1[2] == 3); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(i181.s1[3] == 4); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(i181.i == 10); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(i181.j == 11); // expected-warning{{UNKNOWN}} + return 0; +} + +// Test array with a symbolic offset. +struct jj { + char s1[2]; + char * s2; +}; + +struct JJ { + struct jj s1[3]; + char * s2; +}; + +int f19(int i) { + struct JJ J0 = {{{1, 2, 0}, {3, 4, 0}, {5, 6, 0}}, 0}; + J0.s2 = strdup("hello"); + J0.s1[0].s2 = strdup("hello"); + J0.s1[1].s2 = strdup("hi"); + J0.s1[2].s2 = strdup("world"); + char input[2] = {'a', 'b'}; + memcpy(J0.s1[i].s1, input, 2); + clang_analyzer_eval(J0.s1[0].s1[0] == 1); // expected-warning{{UNKNOWN}}\ + expected-warning{{Potential leak of memory pointed to by field 's2'}}\ + expected-warning{{Potential leak of memory pointed to by 'J0.s2'}} + clang_analyzer_eval(J0.s1[0].s1[1] == 2); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(J0.s1[1].s1[0] == 3); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(J0.s1[1].s1[1] == 4); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(J0.s1[2].s1[0] == 5); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(J0.s1[2].s1[1] == 6); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(J0.s1[i].s1[0] == 5); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(J0.s1[i].s1[1] == 6); // expected-warning{{UNKNOWN}} + // FIXME: memory leak warning for J0.s2 should be emitted here instead of after memcpy call. + return 0; // no warning +} + +// Test array with its super region having symbolic offseted regions. +int f20(int i) { + struct aa * a20 = malloc(sizeof(struct aa) * 2); + a20[0].s1[0] = 1; + a20[0].s1[1] = 2; + a20[0].s1[2] = 3; + a20[0].s1[3] = 4; + a20[0].s2 = strdup("hello"); + a20[1].s1[0] = 5; + a20[1].s1[1] = 6; + a20[1].s1[2] = 7; + a20[1].s1[3] = 8; + a20[1].s2 = strdup("world"); + a20[i].s2 = strdup("hola"); + char input[] = {'a', 'b', 'c', 'd'}; + memcpy(a20[0].s1, input, 4); + clang_analyzer_eval(a20[0].s1[0] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a20[0].s1[1] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a20[0].s1[2] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a20[0].s1[3] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a20[0].s2 == 0); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a20[1].s1[0] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a20[1].s1[1] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a20[1].s1[2] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a20[1].s1[3] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a20[1].s2 == 0); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a20[i].s1[0] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a20[i].s1[1] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a20[i].s1[2] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a20[i].s1[3] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a20[i].s2 == 0); // expected-warning{{UNKNOWN}}\ + expected-warning{{Potential leak of memory pointed to by 'a20'}} + + return 0; +} + +// Test array's region and super region both having symbolic offsets. +int f21(int i) { + struct aa * a21 = malloc(sizeof(struct aa) * 2); + a21[0].s1[0] = 1; + a21[0].s1[1] = 2; + a21[0].s1[2] = 3; + a21[0].s1[3] = 4; + a21[0].s2 = 0; + a21[1].s1[0] = 5; + a21[1].s1[1] = 6; + a21[1].s1[2] = 7; + a21[1].s1[3] = 8; + a21[1].s2 = 0; + a21[i].s2 = strdup("hello"); + a21[i].s1[0] = 1; + a21[i].s1[1] = 2; + a21[i].s1[2] = 3; + a21[i].s1[3] = 4; + char input[] = {'a', 'b', 'c', 'd'}; + memcpy(a21[i].s1, input, 4); + clang_analyzer_eval(a21[0].s1[0] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a21[0].s1[1] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a21[0].s1[2] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a21[0].s1[3] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a21[0].s2 == 0); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a21[1].s1[0] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a21[1].s1[1] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a21[1].s1[2] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a21[1].s1[3] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a21[1].s2 == 0); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a21[i].s1[0] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a21[i].s1[1] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a21[i].s1[2] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a21[i].s1[3] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a21[i].s2 == 0); // expected-warning{{UNKNOWN}}\ + expected-warning{{Potential leak of memory pointed to by 'a21'}} + + return 0; +} + +// Test regions aliasing other regions. +struct ll { + char s1[4]; + char * s2; +}; + +struct mm { + char s3[4]; + char * s4; +}; + +int f24() { + struct ll l24 = {{1, 2, 3, 4}, 0}; + struct mm * m24 = (struct mm *)&l24; + m24->s4 = strdup("hello"); + char input[] = {1, 2, 3, 4}; + memcpy(m24->s3, input, 4); + clang_analyzer_eval(m24->s3[0] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m24->s3[1] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m24->s3[2] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m24->s3[3] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(l24.s1[0] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(l24.s1[1] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(l24.s1[2] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(l24.s1[3] == 1); // expected-warning{{UNKNOWN}}\ + expected-warning{{Potential leak of memory pointed to by field 's4'}} + return 0; +} + +// Test region with potential aliasing and symbolic offsets. +// Store assumes no aliasing. +int f25(int i, int j, struct ll * l, struct mm * m) { + m->s4 = strdup("hola"); // m->s4 not tracked + m->s3[0] = 1; + m->s3[1] = 2; + m->s3[2] = 3; + m->s3[3] = 4; + m->s3[j] = 5; // invalidates m->s3 + l->s2 = strdup("hello"); // l->s2 not tracked + l->s1[0] = 6; + l->s1[1] = 7; + l->s1[2] = 8; + l->s1[3] = 9; + l->s1[i] = 10; // invalidates l->s1 + char input[] = {1, 2, 3, 4}; + memcpy(m->s3, input, 4); // does not invalidate l->s1[i] + clang_analyzer_eval(m->s3[0] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m->s3[1] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m->s3[2] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m->s3[3] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m->s3[i] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m->s3[j] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(l->s1[0] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(l->s1[1] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(l->s1[2] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(l->s1[3] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(l->s1[i] == 1); // expected-warning{{FALSE}} + clang_analyzer_eval(l->s1[j] == 1); // expected-warning{{UNKNOWN}} + return 0; +} + +// Test size with symbolic size argument. +int f26(int i) { + struct aa a26 = {{1, 2, 3, 4}, 0}; + a26.s2 = strdup("hello"); + char input[] = {'a', 'b', 'c', 'd'}; + memcpy(a26.s1, input, i); // i assumed in bound + clang_analyzer_eval(a26.s1[0] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a26.s1[1] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a26.s1[2] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a26.s1[3] == 1); // expected-warning{{UNKNOWN}}\ + expected-warning{{Potential leak of memory pointed to by 'a26.s2'}} + return 0; +} + +// Test sizeof as a size argument. +int f261() { + struct aa a261 = {{1, 2, 3, 4}, 0}; + a261.s2 = strdup("hello"); + char input[] = {'a', 'b', 'c', 'd'}; + memcpy(a261.s1, input, sizeof(a261.s1)); + clang_analyzer_eval(a261.s1[0] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a261.s1[1] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a261.s1[2] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a261.s1[3] == 1); // expected-warning{{UNKNOWN}}\ + expected-warning{{Potential leak of memory pointed to by 'a261.s2'}} + return 0; +} + +// Test negative size argument. +int f262() { + struct aa a262 = {{1, 2, 3, 4}, 0}; + a262.s2 = strdup("hello"); + char input[] = {'a', 'b', 'c', 'd'}; + memcpy(a262.s1, input, -1); + clang_analyzer_eval(a262.s1[0] == 1); // expected-warning{{UNKNOWN}}\ + expected-warning{{Potential leak of memory pointed to by 'a262.s2'}} + clang_analyzer_eval(a262.s1[1] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a262.s1[2] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(a262.s1[3] == 1); // expected-warning{{UNKNOWN}} + return 0; +} + +// Test size argument being an unknown value. +struct xx { + char s1[4]; + char * s2; +}; + +int f263(int n, char * len) { + struct xx x263 = {0}; + x263.s2 = strdup("hello"); + char input[] = {'a', 'b', 'c', 'd'}; + memcpy(x263.s1, input, *(len + n)); + clang_analyzer_eval(x263.s1[0] == 0); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(x263.s1[1] == 0); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(x263.s1[2] == 0); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(x263.s1[3] == 0); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(x263.s2 == 0); // expected-warning{{UNKNOWN}} + return 0; // expected-warning{{Potential leak of memory pointed to by 'x263.s2'}} +} + + +// Test casting regions with symbolic offseted sub regions. +int f27(int i) { + struct mm m27 = {{1, 2, 3, 4}, 0}; + m27.s4 = strdup("hello"); + m27.s3[i] = 5; + char input[] = {'a', 'b', 'c', 'd'}; + memcpy(((struct ll*)(&m27))->s1, input, 4); + clang_analyzer_eval(m27.s3[0] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m27.s3[1] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m27.s3[2] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m27.s3[3] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m27.s3[i] == 1); // expected-warning{{UNKNOWN}}\ + expected-warning{{Potential leak of memory pointed to by 'm27.s4'}} + return 0; +} + +int f28(int i, int j, int k, int l) { + struct mm m28[2]; + m28[i].s4 = strdup("hello"); + m28[j].s3[k] = 1; + struct ll * l28 = (struct ll*)(&m28[1]); + l28->s1[l] = 2; + char input[] = {'a', 'b', 'c', 'd'}; + memcpy(l28->s1, input, 4); + clang_analyzer_eval(m28[0].s3[0] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m28[0].s3[1] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m28[0].s3[2] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m28[0].s3[3] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m28[1].s3[0] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m28[1].s3[1] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m28[1].s3[2] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m28[1].s3[3] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m28[i].s3[0] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m28[i].s3[1] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m28[i].s3[2] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m28[i].s3[3] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m28[j].s3[k] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(l28->s1[l] == 2); // expected-warning{{UNKNOWN}} + return 0; +} + +int f29(int i, int j, int k, int l, int m) { + struct mm m29[2]; + m29[i].s4 = strdup("hello"); + m29[j].s3[k] = 1; + struct ll * l29 = (struct ll*)(&m29[l]); + l29->s1[m] = 2; + char input[] = {'a', 'b', 'c', 'd'}; + memcpy(l29->s1, input, 4); + clang_analyzer_eval(m29[0].s3[0] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m29[0].s3[1] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m29[0].s3[2] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m29[0].s3[3] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m29[1].s3[0] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m29[1].s3[1] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m29[1].s3[2] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m29[1].s3[3] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m29[i].s3[0] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m29[i].s3[1] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m29[i].s3[2] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m29[i].s3[3] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(m29[j].s3[k] == 1); // expected-warning{{TRUE}}\ + expected-warning{{Potential leak of memory pointed to by field 's4'}} + clang_analyzer_eval(l29->s1[m] == 2); // expected-warning{{UNKNOWN}} + return 0; +} + +// Test unions' fields. +union uu { + char x; + char s1[4]; +}; + +int f30() { + union uu u30 = { .s1 = {1, 2, 3, 4}}; + char input[] = {1, 2, 3, 4}; + memcpy(u30.s1, input, 4); + clang_analyzer_eval(u30.s1[0] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(u30.s1[1] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(u30.s1[2] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(u30.s1[3] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(u30.x == 1); // expected-warning{{UNKNOWN}} + return 0; +} + +struct kk { + union uu u; + char * s2; +}; + +int f31() { + struct kk k31; + k31.s2 = strdup("hello"); + k31.u.x = 1; + char input[] = {'a', 'b', 'c', 'd'}; + memcpy(k31.u.s1, input, 4); + clang_analyzer_eval(k31.u.s1[0] == 1); // expected-warning{{UNKNOWN}}\ + expected-warning{{Potential leak of memory pointed to by 'k31.s2'}} + clang_analyzer_eval(k31.u.s1[1] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(k31.u.s1[2] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(k31.u.s1[3] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(k31.u.x == 1); // expected-warning{{UNKNOWN}} + // FIXME: memory leak warning for k31.s2 should be emitted here. + return 0; +} + +union vv { + int x; + char * s2; +}; + +int f32() { + union vv v32; + v32.s2 = strdup("hello"); + char input[] = {'a', 'b', 'c', 'd'}; + memcpy(v32.s2, input, 4); + clang_analyzer_eval(v32.s2[0] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(v32.s2[1] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(v32.s2[2] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(v32.s2[3] == 1); // expected-warning{{UNKNOWN}}\ + expected-warning{{Potential leak of memory pointed to by 'v32.s2'}} + return 0; +} + +struct nn { + int s1; + int i; + int j; + int k; + char * s2; +}; + +// Test bad types to dest buffer. +int f33() { + struct nn n33 = {1, 2, 3, 4, 0}; + n33.s2 = strdup("hello"); + char input[] = {'a', 'b', 'c', 'd'}; + memcpy(n33.s1, input, 4); // expected-warning{{incompatible integer to pointer conversion passing 'int' to parameter of type 'void *'}} + clang_analyzer_eval(n33.i == 2); // expected-warning{{TRUE}} + clang_analyzer_eval(n33.j == 3); // expected-warning{{TRUE}} + clang_analyzer_eval(n33.k == 4); // expected-warning{{TRUE}} + clang_analyzer_eval(((char*)(n33.s1))[0] == 1); // expected-warning{{UNKNOWN}}\ + expected-warning{{cast to 'char *' from smaller integer type 'int'}} + clang_analyzer_eval(((char*)(n33.s1))[1] == 1); // expected-warning{{UNKNOWN}}\ + expected-warning{{cast to 'char *' from smaller integer type 'int'}} + clang_analyzer_eval(((char*)(n33.s1))[2] == 1); // expected-warning{{UNKNOWN}}\ + expected-warning{{cast to 'char *' from smaller integer type 'int'}} + clang_analyzer_eval(((char*)(n33.s1))[3] == 1); // expected-warning{{UNKNOWN}}\ + expected-warning{{cast to 'char *' from smaller integer type 'int'}} + clang_analyzer_eval(n33.s2 == 0); //expected-warning{{UNKNOWN}} + return 0; // expected-warning{{Potential leak of memory pointed to by 'n33.s2'}} +} + +// Test destination buffer being an unknown value. +struct ww { + int s1[4]; + char s2; +}; + +int f34(struct ww * w34, int n) { + w34->s2 = 3; + char input[] = {'a', 'b', 'c', 'd'}; + memcpy(w34->s1 + n, input , 4); + clang_analyzer_eval(w34->s1[0] == 0); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(w34->s1[1] == 0); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(w34->s1[2] == 0); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(w34->s1[3] == 0); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(w34->s1[n] == 0); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(w34->s2 == 3); // expected-warning{{TRUE}} + return 0; +} + +// Test dest buffer as an element region with a symbolic index and size parameter as a symbolic value. +struct yy { + char s1[4]; + char * s2; +}; + +int f35(int i, int n) { + struct yy y35 = {{1, 2, 3, 4}, 0}; + y35.s2 = strdup("hello"); + char input[] = {'a', 'b', 'c', 'd'}; + memcpy(&(y35.s1[i]), input, n); + clang_analyzer_eval(y35.s1[0] == 0); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(y35.s1[1] == 0); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(y35.s1[2] == 0); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(y35.s1[3] == 0); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(y35.s1[i] == 0); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(y35.s2 == 0); // expected-warning{{UNKNOWN}} + return 0; // expected-warning{{Potential leak of memory pointed to by 'y35.s2'}} +} + +// Test regions with negative offsets. +struct zz { + char s1[4]; + int s2; +}; + +int f36(struct zz * z36) { + + char input[] = {'a', 'b', 'c', 'd'}; + z36->s1[0] = 0; + z36->s1[1] = 1; + z36->s1[2] = 2; + z36->s1[3] = 3; + z36->s2 = 10; + + z36 = z36 - 1; // Decrement by 8 bytes (struct zz is 8 bytes). + + z36->s1[0] = 4; + z36->s1[1] = 5; + z36->s1[2] = 6; + z36->s1[3] = 7; + z36->s2 = 11; + + memcpy(z36->s1, input, 4); + + clang_analyzer_eval(z36->s1[0] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(z36->s1[1] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(z36->s1[2] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(z36->s1[3] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(z36->s2 == 11); // expected-warning{{TRUE}} + + z36 = z36 + 1; // Increment back. + + clang_analyzer_eval(z36->s1[0] == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(z36->s1[1] == 1); // expected-warning{{TRUE}} + clang_analyzer_eval(z36->s1[2] == 2); // expected-warning{{TRUE}} + clang_analyzer_eval(z36->s1[3] == 3); // expected-warning{{TRUE}} + clang_analyzer_eval(z36->s2 == 10); // expected-warning{{TRUE}} + + return 0; +} + +int f37(struct zz * z37) { + + char input[] = {'a', 'b', 'c', 'd'}; + z37->s1[0] = 0; + z37->s1[1] = 1; + z37->s1[2] = 2; + z37->s1[3] = 3; + z37->s2 = 10; + + z37 = (struct zz *)((char*)(z37) - 4); // Decrement by 4 bytes (struct zz is 8 bytes). + + z37->s1[0] = 4; + z37->s1[1] = 5; + z37->s1[2] = 6; + z37->s1[3] = 7; + z37->s2 = 11; + + memcpy(z37->s1, input, 4); + + clang_analyzer_eval(z37->s1[0] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(z37->s1[1] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(z37->s1[2] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(z37->s1[3] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(z37->s2 == 11); // expected-warning{{TRUE}} + + z37 = (struct zz *)((char*)(z37) + 4); // Increment back. + + clang_analyzer_eval(z37->s1[0] == 11); // expected-warning{{TRUE}} + clang_analyzer_eval(z37->s1[1] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(z37->s1[2] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(z37->s1[3] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(z37->s2 == 10); // expected-warning{{TRUE}} + + return 0; +} + +int f38(struct zz * z38) { + + char input[] = {'a', 'b', 'c', 'd'}; + z38->s1[0] = 0; + z38->s1[1] = 1; + z38->s1[2] = 2; + z38->s1[3] = 3; + z38->s2 = 10; + + z38 = (struct zz *)((char*)(z38) - 2); // Decrement by 2 bytes (struct zz is 8 bytes). + + z38->s1[0] = 4; + z38->s1[1] = 5; + z38->s1[2] = 6; + z38->s1[3] = 7; + z38->s2 = 11; + + memcpy(z38->s1, input, 4); + + clang_analyzer_eval(z38->s1[0] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(z38->s1[1] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(z38->s1[2] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(z38->s1[3] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(z38->s2 == 11); // expected-warning{{TRUE}} + + z38 = (struct zz *)((char*)(z38) + 2); // Increment back. + + clang_analyzer_eval(z38->s1[0] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(z38->s1[1] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(z38->s1[2] == 11); // expected-warning{{TRUE}} + clang_analyzer_eval(z38->s1[3] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(z38->s2 == 10); // expected-warning{{UNKNOWN}} + + return 0; +} + +// Test negative offsets with a different structure layout. +struct z0 { + int s2; + char s1[4]; +}; + +int f39(struct z0 * d39) { + + char input[] = {'a', 'b', 'c', 'd'}; + d39->s1[0] = 0; + d39->s1[1] = 1; + d39->s1[2] = 2; + d39->s1[3] = 3; + d39->s2 = 10; + + d39 = (struct z0 *)((char*)(d39) - 2); // Decrement by 2 bytes (struct z0 is 8 bytes). + + d39->s1[0] = 4; + d39->s1[1] = 5; + d39->s1[2] = 6; + d39->s1[3] = 7; + d39->s2 = 11; + + memcpy(d39->s1, input, 4); + + clang_analyzer_eval(d39->s1[0] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(d39->s1[1] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(d39->s1[2] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(d39->s1[3] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(d39->s2 == 11); // expected-warning{{TRUE}} + + d39 = (struct z0 *)((char*)(d39) + 2); // Increment back. + + clang_analyzer_eval(d39->s1[0] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(d39->s1[1] == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(d39->s1[2] == 2); // expected-warning{{TRUE}} + clang_analyzer_eval(d39->s1[3] == 3); // expected-warning{{TRUE}} + // FIXME: d39->s2 should evaluate to at least UNKNOWN or FALSE, + // 'collectSubRegionBindings(...)' in RegionStore.cpp will need to + // handle a regions' upper boundary overflowing. + clang_analyzer_eval(d39->s2 == 10); // expected-warning{{TRUE}} + + return 0; +} + |

