222 lines
6.7 KiB
C
222 lines
6.7 KiB
C
|
// 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_eval(int);
|
||
|
void clang_analyzer_warnIfReached();
|
||
|
|
||
|
int getInt();
|
||
|
|
||
|
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)
|
||
|
;
|
||
|
}
|