Files
clang-p2996/clang/test/Analysis/equality_tracking.c
Valeriy Savchenko 60bd8cbc0c [analyzer][solver][NFC] Refactor how we detect (dis)equalities
This patch simplifies the way we deal with (dis)equalities.
Due to the symmetry between constraint handler and range inferrer,
we can have very similar implementations of logic handling
questions about (dis)equality and assumptions involving (dis)equality.

It also helps us to remove one more visitor, and removes uncertainty
that we got all the right places to put `trackNE` and `trackEQ`.

Differential Revision: https://reviews.llvm.org/D105693
2021-07-13 21:00:30 +03:00

236 lines
7.1 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)
;
}
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}}
}
}