| // 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}} |
| } |
| |
| 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 |
| } |
| } |
| } |
| } |
| } |