[analyzer] Rework both constraint managers to handle mixed-type comparisons.
This involves keeping track of three separate types: the symbol type, the
adjustment type, and the comparison type. For example, in "$x + 5 > 0ULL",
if the type of $x is 'signed char', the adjustment type is 'int' and the
comparison type is 'unsigned long long'. Most of the time these three types
will be the same, but we should still do the right thing when the
comparison value is out of range, and wraparound should be calculated in
the adjustment type.
This also re-disables an out-of-bounds test; we were extracting the symbol
from non-additive SymIntExprs, but then throwing away the integer.
Sorry for the large patch; both the basic and range constraint managers needed
to be updated together, since they share code in SimpleConstraintManager.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@156361 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/Analysis/additive-folding.cpp b/test/Analysis/additive-folding.cpp
index 3c9bf3b..136dc08 100644
--- a/test/Analysis/additive-folding.cpp
+++ b/test/Analysis/additive-folding.cpp
@@ -7,6 +7,8 @@
void free(void *);
#define NULL ((void*)0)
#define UINT_MAX (~0U)
+#define INT_MAX (UINT_MAX & (UINT_MAX >> 1))
+#define INT_MIN (-INT_MAX - 1)
//---------------
// Plus/minus
@@ -203,6 +205,140 @@
}
+// Tautologies from outside the range of the symbol
+void tautologyOutsideGT(unsigned char a) {
+ void *b = malloc(1);
+ if (a > 0x100)
+ return; // expected-warning{{never executed}}
+ if (a > -1)
+ free(b);
+ return; // no-warning
+}
+
+void tautologyOutsideGE(unsigned char a) {
+ void *b = malloc(1);
+ if (a >= 0x100)
+ return; // expected-warning{{never executed}}
+ if (a >= -1)
+ free(b);
+ return; // no-warning
+}
+
+void tautologyOutsideLT(unsigned char a) {
+ void *b = malloc(1);
+ if (a < -1)
+ return; // expected-warning{{never executed}}
+ if (a < 0x100)
+ free(b);
+ return; // no-warning
+}
+
+void tautologyOutsideLE (unsigned char a) {
+ void *b = malloc(1);
+ if (a <= -1)
+ return; // expected-warning{{never executed}}
+ if (a <= 0x100)
+ free(b);
+ return; // no-warning
+}
+
+void tautologyOutsideEQ(unsigned char a) {
+ if (a == 0x100)
+ malloc(1); // expected-warning{{never executed}}
+ if (a == -1)
+ malloc(1); // expected-warning{{never executed}}
+}
+
+void tautologyOutsideNE(unsigned char a) {
+ void *sentinel = malloc(1);
+ if (a != 0x100)
+ free(sentinel);
+
+ sentinel = malloc(1);
+ if (a != -1)
+ free(sentinel);
+}
+
+
+// Wraparound with mixed types. Note that the analyzer assumes
+// -fwrapv semantics.
+void mixedWraparoundSanityCheck(int a) {
+ int max = INT_MAX;
+ int min = INT_MIN;
+
+ int b = a + 1;
+ if (a == max && b != min)
+ return; // expected-warning{{never executed}}
+}
+
+void mixedWraparoundGT(int a) {
+ int max = INT_MAX;
+
+ if ((a + 2) > (max + 1LL))
+ return; // expected-warning{{never executed}}
+}
+
+void mixedWraparoundGE(int a) {
+ int max = INT_MAX;
+ int min = INT_MIN;
+
+ if ((a + 2) >= (max + 1LL))
+ return; // expected-warning{{never executed}}
+
+ void *sentinel = malloc(1);
+ if ((a - 2LL) >= min)
+ free(sentinel);
+ return; // expected-warning{{leak}}
+}
+
+void mixedWraparoundLT(int a) {
+ int min = INT_MIN;
+
+ if ((a - 2) < (min - 1LL))
+ return; // expected-warning{{never executed}}
+}
+
+void mixedWraparoundLE(int a) {
+ int max = INT_MAX;
+ int min = INT_MIN;
+
+ if ((a - 2) <= (min - 1LL))
+ return; // expected-warning{{never executed}}
+
+ void *sentinel = malloc(1);
+ if ((a + 2LL) <= max)
+ free(sentinel);
+ return; // expected-warning{{leak}}
+}
+
+void mixedWraparoundEQ(int a) {
+ int max = INT_MAX;
+
+ if ((a + 2) == (max + 1LL))
+ return; // expected-warning{{never executed}}
+}
+
+void mixedWraparoundNE(int a) {
+ int max = INT_MAX;
+
+ void *sentinel = malloc(1);
+ if ((a + 2) != (max + 1LL))
+ free(sentinel);
+ return; // no-warning
+}
+
+
+// Mixed-signedness comparisons.
+void mixedSignedness(int a, unsigned b) {
+ int sMin = INT_MIN;
+ unsigned uMin = INT_MIN;
+ if (a == sMin && a != uMin)
+ return; // expected-warning{{never executed}}
+ if (b == uMin && b != sMin)
+ return; // expected-warning{{never executed}}
+}
+
+
// PR12206/12510 - When SimpleSValBuilder figures out that a symbol is fully
// constrained, it should cast the value to the result type in a binary
// operation...unless the binary operation is a comparison, in which case the
@@ -268,3 +404,13 @@
if (value == (local + 1))
malloc(1); // expected-warning{{never executed}}
}
+
+void multiplicativeSanityTest(int x) {
+ // At one point we were ignoring the *4 completely -- the constraint manager
+ // would see x < 8 and then declare the next part unreachable.
+ if (x*4 < 8)
+ return;
+ if (x == 3)
+ malloc(1);
+ return; // expected-warning{{leak}}
+}