| // RUN: %clang_analyze_cc1 -verify %s \ | |
| // RUN: -analyzer-checker=core,debug.ExprInspection \ | |
| // RUN: -analyzer-config eagerly-assume=false | |
| #define NULL (void *)0 | |
| #define UCHAR_MAX (unsigned char)(~0U) | |
| #define CHAR_MAX (char)(UCHAR_MAX & (UCHAR_MAX >> 1)) | |
| #define CHAR_MIN (char)(UCHAR_MAX & ~(UCHAR_MAX >> 1)) | |
| void clang_analyzer_value(int); | |
| void clang_analyzer_eval(int); | |
| void clang_analyzer_warnIfReached(void); | |
| int getInt(void); | |
| void zeroImpliesEquality(int a, int b) { | |
| clang_analyzer_eval((a - b) == 0); // expected-warning{{UNKNOWN}} | |
| if ((a - b) == 0) { | |
| clang_analyzer_eval(b != a); // expected-warning{{FALSE}} | |
| clang_analyzer_eval(b == a); // expected-warning{{TRUE}} | |
| clang_analyzer_eval(!(a != b)); // expected-warning{{TRUE}} | |
| clang_analyzer_eval(!(b == a)); // expected-warning{{FALSE}} | |
| return; | |
| } | |
| clang_analyzer_eval((a - b) == 0); // expected-warning{{FALSE}} | |
| clang_analyzer_eval(b == a); // expected-warning{{FALSE}} | |
| clang_analyzer_eval(b != a); // expected-warning{{TRUE}} | |
| } | |
| typedef int I32_A; | |
| typedef int I32_B; | |
| void zeroImpliesEqualityWithTypedef(I32_A a, I32_B b) { | |
| clang_analyzer_eval((a - b) == 0); // expected-warning{{UNKNOWN}} | |
| if ((a - b) == 0) { | |
| clang_analyzer_eval(b != a); // expected-warning{{FALSE}} | |
| clang_analyzer_eval(b == a); // expected-warning{{TRUE}} | |
| clang_analyzer_eval(!(a != b)); // expected-warning{{TRUE}} | |
| clang_analyzer_eval(!(b == a)); // expected-warning{{FALSE}} | |
| return; | |
| } | |
| clang_analyzer_eval((a - b) == 0); // expected-warning{{FALSE}} | |
| clang_analyzer_eval(b == a); // expected-warning{{FALSE}} | |
| clang_analyzer_eval(b != a); // expected-warning{{TRUE}} | |
| } | |
| void zeroImpliesReversedEqual(int a, int b) { | |
| clang_analyzer_eval((b - a) == 0); // expected-warning{{UNKNOWN}} | |
| if ((b - a) == 0) { | |
| clang_analyzer_eval(b != a); // expected-warning{{FALSE}} | |
| clang_analyzer_eval(b == a); // expected-warning{{TRUE}} | |
| return; | |
| } | |
| clang_analyzer_eval((b - a) == 0); // expected-warning{{FALSE}} | |
| clang_analyzer_eval(b == a); // expected-warning{{FALSE}} | |
| clang_analyzer_eval(b != a); // expected-warning{{TRUE}} | |
| } | |
| void canonicalEqual(int a, int b) { | |
| clang_analyzer_eval(a == b); // expected-warning{{UNKNOWN}} | |
| if (a == b) { | |
| clang_analyzer_eval(b == a); // expected-warning{{TRUE}} | |
| return; | |
| } | |
| clang_analyzer_eval(a == b); // expected-warning{{FALSE}} | |
| clang_analyzer_eval(b == a); // expected-warning{{FALSE}} | |
| } | |
| void test(int a, int b, int c, int d) { | |
| if (a == b && c == d) { | |
| if (a == 0 && b == d) { | |
| clang_analyzer_eval(c == 0); // expected-warning{{TRUE}} | |
| } | |
| c = 10; | |
| if (b == d) { | |
| clang_analyzer_eval(c == 10); // expected-warning{{TRUE}} | |
| clang_analyzer_eval(d == 10); // expected-warning{{UNKNOWN}} | |
| // expected-warning@-1{{FALSE}} | |
| clang_analyzer_eval(b == a); // expected-warning{{TRUE}} | |
| clang_analyzer_eval(a == d); // expected-warning{{TRUE}} | |
| b = getInt(); | |
| clang_analyzer_eval(a == d); // expected-warning{{TRUE}} | |
| clang_analyzer_eval(a == b); // expected-warning{{UNKNOWN}} | |
| } | |
| } | |
| if (a != b && b == c) { | |
| if (c == 42) { | |
| clang_analyzer_eval(b == 42); // expected-warning{{TRUE}} | |
| clang_analyzer_eval(a != 42); // expected-warning{{TRUE}} | |
| } | |
| } | |
| } | |
| void testIntersection(int a, int b, int c) { | |
| if (a < 42 && b > 15 && c >= 25 && c <= 30) { | |
| if (a != b) | |
| return; | |
| clang_analyzer_eval(a > 15); // expected-warning{{TRUE}} | |
| clang_analyzer_eval(b < 42); // expected-warning{{TRUE}} | |
| clang_analyzer_eval(a <= 30); // expected-warning{{UNKNOWN}} | |
| if (c == b) { | |
| // For all equal symbols, we should track the minimal common range. | |
| // | |
| // Also, it should be noted that c is dead at this point, but the | |
| // constraint initially associated with c is still around. | |
| clang_analyzer_eval(a >= 25 && a <= 30); // expected-warning{{TRUE}} | |
| clang_analyzer_eval(b >= 25 && b <= 30); // expected-warning{{TRUE}} | |
| } | |
| } | |
| } | |
| void testPromotion(int a, char b) { | |
| if (b > 10) { | |
| if (a == b) { | |
| // FIXME: support transferring char ranges onto equal int symbols | |
| // when char is promoted to int | |
| clang_analyzer_eval(a > 10); // expected-warning{{UNKNOWN}} | |
| clang_analyzer_eval(a <= CHAR_MAX); // expected-warning{{UNKNOWN}} | |
| } | |
| } | |
| } | |
| void testPromotionOnlyTypes(int a, char b) { | |
| if (a == b) { | |
| // FIXME: support transferring char ranges onto equal int symbols | |
| // when char is promoted to int | |
| clang_analyzer_eval(a <= CHAR_MAX); // expected-warning{{UNKNOWN}} | |
| } | |
| } | |
| void testDowncast(int a, unsigned char b) { | |
| if (a <= -10) { | |
| if ((unsigned char)a == b) { | |
| // Even though ranges for a and b do not intersect, | |
| // ranges for (unsigned char)a and b do. | |
| clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} | |
| } | |
| if (a == b) { | |
| // FIXME: This case on the other hand is different, it shouldn't be | |
| // reachable. However, the corrent symbolic information available | |
| // to the solver doesn't allow it to distinguish this expression | |
| // from the previous one. | |
| clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} | |
| } | |
| } | |
| } | |
| void testPointers(int *a, int *b, int *c, int *d) { | |
| if (a == b && c == d) { | |
| if (a == NULL && b == d) { | |
| clang_analyzer_eval(c == NULL); // expected-warning{{TRUE}} | |
| } | |
| } | |
| if (a != b && b == c) { | |
| if (c == NULL) { | |
| clang_analyzer_eval(a != NULL); // expected-warning{{TRUE}} | |
| } | |
| } | |
| } | |
| void testDisequalitiesAfter(int a, int b, int c) { | |
| if (a >= 10 && b <= 42) { | |
| if (a == b && c == 15 && c != a) { | |
| clang_analyzer_eval(b != c); // expected-warning{{TRUE}} | |
| clang_analyzer_eval(a != 15); // expected-warning{{TRUE}} | |
| clang_analyzer_eval(b != 15); // expected-warning{{TRUE}} | |
| clang_analyzer_eval(b >= 10); // expected-warning{{TRUE}} | |
| clang_analyzer_eval(a <= 42); // expected-warning{{TRUE}} | |
| } | |
| } | |
| } | |
| void testDisequalitiesBefore(int a, int b, int c) { | |
| if (a >= 10 && b <= 42 && c == 15) { | |
| if (a == b && c != a) { | |
| clang_analyzer_eval(b != c); // expected-warning{{TRUE}} | |
| clang_analyzer_eval(a != 15); // expected-warning{{TRUE}} | |
| clang_analyzer_eval(b != 15); // expected-warning{{TRUE}} | |
| clang_analyzer_eval(b >= 10); // expected-warning{{TRUE}} | |
| clang_analyzer_eval(a <= 42); // expected-warning{{TRUE}} | |
| } | |
| } | |
| } | |
| void avoidInfeasibleConstraintsForClasses(int a, int b) { | |
| if (a >= 0 && a <= 10 && b >= 20 && b <= 50) { | |
| if ((b - a) == 0) { | |
| clang_analyzer_warnIfReached(); // no warning | |
| } | |
| if (a == b) { | |
| clang_analyzer_warnIfReached(); // no warning | |
| } | |
| if (a != b) { | |
| clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} | |
| } else { | |
| clang_analyzer_warnIfReached(); // no warning | |
| } | |
| } | |
| } | |
| void avoidInfeasibleConstraintforGT(int a, int b) { | |
| int c = b - a; | |
| if (c <= 0) | |
| return; | |
| // c > 0 | |
| // b - a > 0 | |
| // b > a | |
| if (a != b) { | |
| clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} | |
| return; | |
| } | |
| clang_analyzer_warnIfReached(); // no warning | |
| // a == b | |
| if (c < 0) | |
| ; | |
| } | |
| void avoidInfeasibleConstraintforLT(int a, int b) { | |
| int c = b - a; | |
| if (c >= 0) | |
| return; | |
| // c < 0 | |
| // b - a < 0 | |
| // b < a | |
| if (a != b) { | |
| clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} | |
| return; | |
| } | |
| clang_analyzer_warnIfReached(); // no warning | |
| // a == b | |
| if (c < 0) | |
| ; | |
| } | |
| void implyDisequalityFromGT(int a, int b) { | |
| if (a > b) { | |
| clang_analyzer_eval(a == b); // expected-warning{{FALSE}} | |
| clang_analyzer_eval(a != b); // expected-warning{{TRUE}} | |
| } | |
| } | |
| void implyDisequalityFromLT(int a, int b) { | |
| if (a < b) { | |
| clang_analyzer_eval(a == b); // expected-warning{{FALSE}} | |
| clang_analyzer_eval(a != b); // expected-warning{{TRUE}} | |
| } | |
| } | |
| void deletePointBefore(int x, int tmp) { | |
| if(tmp == 0) | |
| if(x != tmp) | |
| clang_analyzer_value(x); // expected-warning {{32s:{ [-2147483648, -1], [1, 2147483647] }}} | |
| } | |
| void deletePointAfter(int x, int tmp) { | |
| if(x != tmp) | |
| if(tmp == 2147483647) | |
| clang_analyzer_value(x); // expected-warning {{32s:{ [-2147483648, 2147483646] }}} | |
| } | |
| void deleteTwoPoints(int x, int tmp1, int tmp2) { | |
| if(x != tmp1) { | |
| if (tmp1 == 42 && tmp2 == 87) { | |
| clang_analyzer_value(x); // expected-warning {{32s:{ [-2147483648, 41], [43, 2147483647] }}} | |
| if(x != tmp2) | |
| clang_analyzer_value(x); // expected-warning {{32s:{ [-2147483648, 41], [43, 86], [88, 2147483647] }}} | |
| } | |
| } | |
| } | |
| void deleteAllPoints(unsigned char x, unsigned char *arr) { | |
| #define cond(n) \ | |
| arr[n##0] == n##0 && \ | |
| arr[n##1] == n##1 && \ | |
| arr[n##2] == n##2 && \ | |
| arr[n##3] == n##3 && \ | |
| arr[n##4] == n##4 && \ | |
| arr[n##5] == n##5 && \ | |
| arr[n##6] == n##6 && \ | |
| arr[n##7] == n##7 && \ | |
| arr[n##8] == n##8 && \ | |
| arr[n##9] == n##9 && \ | |
| #define condX(n) \ | |
| arr[n##0] != x && \ | |
| arr[n##1] != x && \ | |
| arr[n##2] != x && \ | |
| arr[n##3] != x && \ | |
| arr[n##4] != x && \ | |
| arr[n##5] != x && \ | |
| arr[n##6] != x && \ | |
| arr[n##7] != x && \ | |
| arr[n##8] != x && \ | |
| arr[n##9] != x && \ | |
| clang_analyzer_value(x); // expected-warning {{{ [0, 255] }}} | |
| if ( | |
| cond() // 0 .. 9 | |
| cond(1) // 10 .. 19 | |
| cond(2) // 20 .. 29 | |
| cond(3) // 30 .. 39 | |
| cond(4) // 40 .. 49 | |
| cond(5) // 50 .. 59 | |
| cond(6) // 60 .. 69 | |
| cond(7) // 70 .. 79 | |
| cond(8) // 80 .. 89 | |
| cond(9) // 90 .. 99 | |
| cond(10) // 100 .. 209 | |
| cond(11) // 110 .. 219 | |
| cond(12) // 120 .. 229 | |
| cond(13) // 130 .. 239 | |
| cond(14) // 140 .. 249 | |
| cond(15) // 150 .. 259 | |
| cond(16) // 160 .. 269 | |
| cond(17) // 170 .. 279 | |
| cond(18) // 180 .. 289 | |
| cond(19) // 190 .. 199 | |
| cond(20) // 200 .. 209 | |
| cond(21) // 210 .. 219 | |
| cond(22) // 220 .. 229 | |
| cond(23) // 230 .. 239 | |
| cond(24) // 240 .. 249 | |
| arr[250] == 250 && | |
| arr[251] == 251 && | |
| arr[252] == 252 && | |
| arr[253] == 253 && | |
| arr[254] == 254 && | |
| arr[255] == 255 | |
| ) { | |
| if ( | |
| condX() // 0 .. 9 | |
| condX(1) // 10 .. 19 | |
| condX(2) // 20 .. 29 | |
| condX(3) // 30 .. 39 | |
| condX(4) // 40 .. 49 | |
| condX(5) // 50 .. 59 | |
| condX(6) // 60 .. 69 | |
| condX(7) // 70 .. 79 | |
| condX(8) // 80 .. 89 | |
| condX(9) // 90 .. 99 | |
| condX(10) // 100 .. 209 | |
| condX(11) // 110 .. 219 | |
| condX(12) // 120 .. 229 | |
| condX(13) // 130 .. 239 | |
| condX(14) // 140 .. 249 | |
| condX(15) // 150 .. 259 | |
| condX(16) // 160 .. 269 | |
| condX(17) // 170 .. 279 | |
| condX(18) // 180 .. 289 | |
| condX(19) // 190 .. 199 | |
| condX(20) // 200 .. 209 | |
| condX(21) // 210 .. 219 | |
| condX(22) // 220 .. 229 | |
| condX(23) // 230 .. 239 | |
| arr[240] != x && | |
| arr[241] != x && | |
| arr[242] != x && | |
| arr[243] != x && | |
| arr[244] != x && | |
| arr[245] != x && | |
| arr[246] != x && | |
| arr[247] != x && | |
| arr[248] != x && | |
| arr[249] != x | |
| ) { | |
| clang_analyzer_value(x); // expected-warning {{{ [250, 255] }}} | |
| if ( | |
| arr[250] != x && | |
| arr[251] != x && | |
| //skip arr[252] | |
| arr[253] != x && | |
| arr[254] != x && | |
| arr[255] != x | |
| ) { | |
| clang_analyzer_value(x); // expected-warning {{32s:252}} | |
| if (arr[252] != x) { | |
| clang_analyzer_warnIfReached(); // unreachable | |
| } | |
| } | |
| } | |
| } | |
| } |