baloghadamsoftware created this revision.
baloghadamsoftware added reviewers: NoQ, dcoughlin.
Herald added subscribers: mikhail.ramalho, a.sidorin, szepet.
Herald added a reviewer: george.karpenkov.
Currently, the default (range-based) constrain manager supports symbolic
expressions of the format "symbol + integer" or "symbol - integer" to compare
them to another integer. However, multiplication and division is not supported
yet.
An example where this lack of support causes false positives is the following:
unsigned size = 32;
int init(int *s);
void assert(int);
static void test(void)
{
int val;
if (size>10 && size<=100){
for (unsigned j = 0; j<size/2; j++)
init(&val);
assert((int) (val == 1)); //False positive: val may be uninitialized
}
}
In this example the loop executes at least 5 times, but the analyzer cannot
deduce this so it assumes that it may be completely skipped, since it cannot
reason about `size/2` even if it knows that size has a range of (10..100] which
is [11..100] among integers.
This patch solves this problem by introducing support for symbols such as
"symbol * integer" or "symbol / integer". In this patch only positive integers
are supported. On the long-term our goal is to extend this support to more
generic first-degree symbolic expressions, e.g. "symbol * integer + another
integer".
https://reviews.llvm.org/D49074
Files:
include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
lib/StaticAnalyzer/Core/RangedConstraintManager.cpp
test/Analysis/constraint_manager_scale.c
Index: test/Analysis/constraint_manager_scale.c
===================================================================
--- /dev/null
+++ test/Analysis/constraint_manager_scale.c
@@ -0,0 +1,175 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=debug.ExprInspection,core.builtin -verify %s
+
+void clang_analyzer_eval(int);
+
+#define UINT_MAX (~0U)
+#define INT_MAX (UINT_MAX & (UINT_MAX >> 1))
+#define INT_MIN (UINT_MAX & ~(UINT_MAX >> 1))
+
+extern void __assert_fail (__const char *__assertion, __const char *__file,
+ unsigned int __line, __const char *__function)
+ __attribute__ ((__noreturn__));
+#define assert(expr) \
+ ((expr) ? (void)(0) : __assert_fail (#expr, __FILE__, __LINE__, __func__))
+
+void add_ne(int x) {
+ assert(x + 1 != 3);
+ clang_analyzer_eval(x == 2); // expected-warning{{FALSE}}
+ clang_analyzer_eval(x == 3); // expected-warning{{UNKNOWN}}
+}
+
+void sub_ne(int x) {
+ assert(x - 1 != 1);
+ clang_analyzer_eval(x == 2); // expected-warning{{FALSE}}
+ clang_analyzer_eval(x == 1); // expected-warning{{UNKNOWN}}
+}
+
+void mult_ne(int x) {
+ assert(x * 2 != 4);
+ clang_analyzer_eval(x == 2); // expected-warning{{FALSE}}
+ clang_analyzer_eval(x == 4); // expected-warning{{UNKNOWN}}
+}
+
+void div_ne(int x) {
+ assert(x / 2 != 1);
+ clang_analyzer_eval(x == 2); // expected-warning{{FALSE}}
+ clang_analyzer_eval(x == 1); // expected-warning{{UNKNOWN}}
+}
+
+void add_eq(int x) {
+ assert(x + 1 == 3);
+ clang_analyzer_eval(x == 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(x == 3); // expected-warning{{FALSE}}
+}
+
+void sub_eq(int x) {
+ assert(x - 1 == 1);
+ clang_analyzer_eval(x == 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(x == 1); // expected-warning{{FALSE}}
+}
+
+void mult_eq(int x) {
+ assert(x * 2 == 4);
+ clang_analyzer_eval(x == 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(x == 4); // expected-warning{{FALSE}}
+}
+
+void div_eq(int x) {
+ assert(x / 2 == 1);
+ clang_analyzer_eval(x == 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(x == 1); // expected-warning{{FALSE}}
+}
+
+void add_lt(int x) {
+ assert(x < INT_MAX);
+ assert(x + 1 < 5);
+ clang_analyzer_eval(x < 4); // expected-warning{{TRUE}}
+ clang_analyzer_eval(x < 3); // expected-warning{{UNKNOWN}}
+}
+
+void sub_lt(int x) {
+ assert(x - 1 < 3);
+ clang_analyzer_eval(x < 4); // expected-warning{{TRUE}}
+ clang_analyzer_eval(x < 3); // expected-warning{{UNKNOWN}}
+}
+
+void mult_lt(int x) {
+ assert(x * 2 < 8);
+ clang_analyzer_eval(x < 4); // expected-warning{{TRUE}}
+ clang_analyzer_eval(x < 2); // expected-warning{{UNKNOWN}}
+}
+
+void div_lt(int x) {
+ assert(x / 2 < 2);
+ clang_analyzer_eval(x < 4); // expected-warning{{TRUE}}
+ clang_analyzer_eval(x < 2); // expected-warning{{UNKNOWN}}
+}
+
+void add_gt(int x) {
+ assert(x + 1 > 3);
+ clang_analyzer_eval(x > 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(x > 3); // expected-warning{{UNKNOWN}}
+}
+
+void sub_gt(int x) {
+ assert(x >= 0);
+ assert(x - 1 > 1);
+ clang_analyzer_eval(x > 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(x > 3); // expected-warning{{UNKNOWN}}
+}
+
+void mult_gt(int x) {
+ assert(x * 2 > 4);
+ clang_analyzer_eval(x > 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(x > 3); // expected-warning{{UNKNOWN}}
+}
+
+void div_gt(int x) {
+ assert(x / 2 > 1);
+ clang_analyzer_eval(x > 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(x > 3); // expected-warning{{UNKNOWN}}
+}
+
+void add_ge(int x) {
+ assert(x + 1 >= 3);
+ clang_analyzer_eval(x >= 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(x >= 3); // expected-warning{{UNKNOWN}}
+}
+
+void sub_ge(int x) {
+ assert(x >= 0);
+ assert(x - 1 >= 1);
+ clang_analyzer_eval(x >= 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(x >= 3); // expected-warning{{UNKNOWN}}
+}
+
+void mult_ge(int x) {
+ assert(x * 2 >= 4);
+ clang_analyzer_eval(x >= 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(x >= 3); // expected-warning{{UNKNOWN}}
+}
+
+void div_ge(int x) {
+ assert(x / 2 >= 1);
+ clang_analyzer_eval(x >= 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(x >= 3); // expected-warning{{UNKNOWN}}
+}
+
+void add_le(int x) {
+ assert(x < INT_MAX);
+ assert(x + 1 <= 5);
+ clang_analyzer_eval(x <= 4); // expected-warning{{TRUE}}
+ clang_analyzer_eval(x <= 3); // expected-warning{{UNKNOWN}}
+}
+
+void sub_le(int x) {
+ assert(x - 1 <= 3);
+ clang_analyzer_eval(x <= 4); // expected-warning{{TRUE}}
+ clang_analyzer_eval(x <= 3); // expected-warning{{UNKNOWN}}
+}
+
+void mult_le(int x) {
+ assert(x * 2 <= 8);
+ clang_analyzer_eval(x <= 4); // expected-warning{{TRUE}}
+ clang_analyzer_eval(x <= 2); // expected-warning{{UNKNOWN}}
+}
+
+void div_le(int x) {
+ assert(x / 2 <= 2);
+ clang_analyzer_eval(x <= 4); // expected-warning{{TRUE}}
+ clang_analyzer_eval(x <= 2); // expected-warning{{UNKNOWN}}
+}
+
+void div_overflow_unsigned(unsigned char x) {
+ assert(x / 2 <= 200);
+ clang_analyzer_eval(x == 0); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(x == 127); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(x == 255); // expected-warning{{UNKNOWN}}
+}
+
+void div_overflow_signed(signed char x) {
+ assert(x / 2 <= 100);
+ clang_analyzer_eval(x == -128); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(x == 0); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(x == 127); // expected-warning{{UNKNOWN}}
+}
Index: lib/StaticAnalyzer/Core/RangedConstraintManager.cpp
===================================================================
--- lib/StaticAnalyzer/Core/RangedConstraintManager.cpp
+++ lib/StaticAnalyzer/Core/RangedConstraintManager.cpp
@@ -77,6 +77,9 @@
BasicValueFactory &BVF = getBasicVals();
APSIntType WraparoundType = BVF.getAPSIntType(Sym->getType());
+ llvm::APFloat Scale = llvm::APFloat(llvm::APFloat::IEEEquad(), 1);
+ computeScale(Sym, Scale);
+
llvm::APSInt Adjustment = WraparoundType.getZeroValue();
SymbolRef AdjustedSym = Sym;
computeAdjustment(AdjustedSym, Adjustment);
@@ -93,9 +96,9 @@
if (InRange)
return assumeSymWithinInclusiveRange(State, AdjustedSym, ConvertedFrom,
- ConvertedTo, Adjustment);
+ ConvertedTo, Scale, Adjustment);
return assumeSymOutsideInclusiveRange(State, AdjustedSym, ConvertedFrom,
- ConvertedTo, Adjustment);
+ ConvertedTo, Scale, Adjustment);
}
ProgramStateRef
@@ -110,10 +113,11 @@
// Reverse the operation and add directly to state.
const llvm::APSInt &Zero = BVF.getValue(0, T);
+ const llvm::APFloat One = llvm::APFloat(llvm::APFloat::IEEEquad(), 1);
if (Assumption)
- return assumeSymNE(State, Sym, Zero, Zero);
+ return assumeSymNE(State, Sym, Zero, One, Zero);
else
- return assumeSymEQ(State, Sym, Zero, Zero);
+ return assumeSymEQ(State, Sym, Zero, One, Zero);
}
ProgramStateRef RangedConstraintManager::assumeSymRel(ProgramStateRef State,
@@ -138,8 +142,19 @@
BasicValueFactory &BVF = getBasicVals();
APSIntType WraparoundType = BVF.getAPSIntType(Sym->getType());
- // We only handle simple comparisons of the form "$sym == constant"
- // or "($sym+constant1) == constant2".
+ // We only handle simple comparisons of the form "$sym == constant",
+ // "($sym*constant0) == constant2" or "($sym+constant1) == constant2".
+ // FIXME: On the long term support first-degree expressions of
+ // "($sym*constant0)+constant1 == constant2"
+
+ // The scale is "constant0" in the above expression. It's used to
+ // "rescale" the solution range. It's up to the subclasses of
+ // SimpleConstraintManager to handle the scaling.
+
+
+ llvm::APFloat Scale = llvm::APFloat(llvm::APFloat::IEEEquad(), 1);
+ computeScale(Sym, Scale);
+
// The adjustment is "constant1" in the above expression. It's used to
// "slide" the solution range around for modular arithmetic. For example,
// x < 4 has the solution [0, 3]. x+2 < 4 has the solution [0-2, 3-2], which
@@ -162,25 +177,47 @@
llvm_unreachable("invalid operation not caught by assertion above");
case BO_EQ:
- return assumeSymEQ(State, Sym, ConvertedInt, Adjustment);
+ return assumeSymEQ(State, Sym, ConvertedInt, Scale, Adjustment);
case BO_NE:
- return assumeSymNE(State, Sym, ConvertedInt, Adjustment);
+ return assumeSymNE(State, Sym, ConvertedInt, Scale, Adjustment);
case BO_GT:
- return assumeSymGT(State, Sym, ConvertedInt, Adjustment);
+ return assumeSymGT(State, Sym, ConvertedInt, Scale, Adjustment);
case BO_GE:
- return assumeSymGE(State, Sym, ConvertedInt, Adjustment);
+ return assumeSymGE(State, Sym, ConvertedInt, Scale, Adjustment);
case BO_LT:
- return assumeSymLT(State, Sym, ConvertedInt, Adjustment);
+ return assumeSymLT(State, Sym, ConvertedInt, Scale, Adjustment);
case BO_LE:
- return assumeSymLE(State, Sym, ConvertedInt, Adjustment);
+ return assumeSymLE(State, Sym, ConvertedInt, Scale, Adjustment);
} // end switch
}
+void RangedConstraintManager::computeScale(SymbolRef &Sym,
+ llvm::APFloat &Scale) {
+ // Is it a "($sym*constant1)" expression?
+ if (const SymIntExpr *SE = dyn_cast<SymIntExpr>(Sym)) {
+ BinaryOperator::Opcode Op = SE->getOpcode();
+ if (Op == BO_Mul || Op == BO_Div) {
+ Sym = SE->getLHS();
+
+ // FIXME: We do not yet support multiplication/division by negative
+ if (SE->getRHS() < 0)
+ return;
+
+ Scale.convertFromAPInt(SE->getRHS(), SE->getRHS().isSigned(),
+ llvm::APFloat::rmTowardZero);
+
+ // Don't forget to reciprocate the scale if it's being divided.
+ if (Op == BO_Div)
+ Scale = llvm::APFloat(llvm::APFloat::IEEEquad(), 1) / Scale;
+ }
+ }
+}
+
void RangedConstraintManager::computeAdjustment(SymbolRef &Sym,
llvm::APSInt &Adjustment) {
// Is it a "($sym+constant1)" expression?
Index: lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===================================================================
--- lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -250,35 +250,43 @@
ProgramStateRef assumeSymNE(ProgramStateRef State, SymbolRef Sym,
const llvm::APSInt &V,
+ const llvm::APFloat &Scale,
const llvm::APSInt &Adjustment) override;
ProgramStateRef assumeSymEQ(ProgramStateRef State, SymbolRef Sym,
const llvm::APSInt &V,
+ const llvm::APFloat &Scale,
const llvm::APSInt &Adjustment) override;
ProgramStateRef assumeSymLT(ProgramStateRef State, SymbolRef Sym,
const llvm::APSInt &V,
+ const llvm::APFloat &Scale,
const llvm::APSInt &Adjustment) override;
ProgramStateRef assumeSymGT(ProgramStateRef State, SymbolRef Sym,
const llvm::APSInt &V,
+ const llvm::APFloat &Scale,
const llvm::APSInt &Adjustment) override;
ProgramStateRef assumeSymLE(ProgramStateRef State, SymbolRef Sym,
const llvm::APSInt &V,
+ const llvm::APFloat &Scale,
const llvm::APSInt &Adjustment) override;
ProgramStateRef assumeSymGE(ProgramStateRef State, SymbolRef Sym,
const llvm::APSInt &V,
+ const llvm::APFloat &Scale,
const llvm::APSInt &Adjustment) override;
ProgramStateRef assumeSymWithinInclusiveRange(
ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From,
- const llvm::APSInt &To, const llvm::APSInt &Adjustment) override;
+ const llvm::APSInt &To, const llvm::APFloat &Scale,
+ const llvm::APSInt &Adjustment) override;
ProgramStateRef assumeSymOutsideInclusiveRange(
ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From,
- const llvm::APSInt &To, const llvm::APSInt &Adjustment) override;
+ const llvm::APSInt &To, const llvm::APFloat &Scale,
+ const llvm::APSInt &Adjustment) override;
private:
RangeSet::Factory F;
@@ -289,20 +297,27 @@
RangeSet getSymLTRange(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Int,
+ const llvm::APFloat &Scale,
const llvm::APSInt &Adjustment);
RangeSet getSymGTRange(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Int,
+ const llvm::APFloat &Scale,
const llvm::APSInt &Adjustment);
RangeSet getSymLERange(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Int,
+ const llvm::APFloat &Scale,
const llvm::APSInt &Adjustment);
RangeSet getSymLERange(llvm::function_ref<RangeSet()> RS,
const llvm::APSInt &Int,
+ const llvm::APFloat &Scale,
const llvm::APSInt &Adjustment);
RangeSet getSymGERange(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Int,
+ const llvm::APFloat &Scale,
const llvm::APSInt &Adjustment);
+ llvm::APSInt rescale(const llvm::APSInt &Int,
+ const llvm::APFloat &Scale) const;
};
} // end anonymous namespace
@@ -508,6 +523,18 @@
return nullptr;
}
+llvm::APSInt RangeConstraintManager::rescale(const llvm::APSInt &Int,
+ const llvm::APFloat &Scale) const {
+ llvm::APFloat Float(llvm::APFloat::IEEEquad(),
+ llvm::APFloat::uninitializedTag());
+ Float.convertFromAPInt(Int, Int.isSigned(), llvm::APFloat::rmTowardZero);
+ llvm::APSInt Result(Int.getBitWidth(), Int.isUnsigned());
+ bool Exact;
+ (Float / Scale).convertToInteger(Result, llvm::APFloat::rmTowardZero, &Exact);
+
+ return Result;
+}
+
//===------------------------------------------------------------------------===
// assumeSymX methods: protected interface for RangeConstraintManager.
//===------------------------------------------------------------------------===/
@@ -523,41 +550,46 @@
ProgramStateRef
RangeConstraintManager::assumeSymNE(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Int,
+ const llvm::APFloat &Scale,
const llvm::APSInt &Adjustment) {
// Before we do any real work, see if the value can even show up.
APSIntType AdjustmentType(Adjustment);
if (AdjustmentType.testInRange(Int, true) != APSIntType::RTR_Within)
return St;
- llvm::APSInt Lower = AdjustmentType.convert(Int) - Adjustment;
+ llvm::APSInt ScInt = rescale(Int, Scale);
+ llvm::APSInt Lower = AdjustmentType.convert(ScInt) - Adjustment;
llvm::APSInt Upper = Lower;
--Lower;
++Upper;
- // [Int-Adjustment+1, Int-Adjustment-1]
+ // [Int/Scale-Adjustment+1, Int/Scale-Adjustment-1]
// Notice that the lower bound is greater than the upper bound.
RangeSet New = getRange(St, Sym).Intersect(getBasicVals(), F, Upper, Lower);
return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New);
}
ProgramStateRef
RangeConstraintManager::assumeSymEQ(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Int,
+ const llvm::APFloat &Scale,
const llvm::APSInt &Adjustment) {
// Before we do any real work, see if the value can even show up.
APSIntType AdjustmentType(Adjustment);
if (AdjustmentType.testInRange(Int, true) != APSIntType::RTR_Within)
return nullptr;
- // [Int-Adjustment, Int-Adjustment]
- llvm::APSInt AdjInt = AdjustmentType.convert(Int) - Adjustment;
+ // [Int/Scale-Adjustment, Int/Scale-Adjustment]
+ llvm::APSInt ScInt = rescale(Int, Scale);
+ llvm::APSInt AdjInt = AdjustmentType.convert(ScInt) - Adjustment;
RangeSet New = getRange(St, Sym).Intersect(getBasicVals(), F, AdjInt, AdjInt);
return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New);
}
RangeSet RangeConstraintManager::getSymLTRange(ProgramStateRef St,
SymbolRef Sym,
const llvm::APSInt &Int,
+ const llvm::APFloat &Scale,
const llvm::APSInt &Adjustment) {
// Before we do any real work, see if the value can even show up.
APSIntType AdjustmentType(Adjustment);
@@ -570,8 +602,10 @@
return getRange(St, Sym);
}
- // Special case for Int == Min. This is always false.
- llvm::APSInt ComparisonVal = AdjustmentType.convert(Int);
+ llvm::APSInt ScInt = rescale(Int, Scale);
+
+ // Special case for ScInt == Min. This is always false.
+ llvm::APSInt ComparisonVal = AdjustmentType.convert(ScInt);
llvm::APSInt Min = AdjustmentType.getMinValue();
if (ComparisonVal == Min)
return F.getEmptySet();
@@ -586,14 +620,16 @@
ProgramStateRef
RangeConstraintManager::assumeSymLT(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Int,
+ const llvm::APFloat &Scale,
const llvm::APSInt &Adjustment) {
- RangeSet New = getSymLTRange(St, Sym, Int, Adjustment);
+ RangeSet New = getSymLTRange(St, Sym, Int, Scale, Adjustment);
return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New);
}
RangeSet RangeConstraintManager::getSymGTRange(ProgramStateRef St,
SymbolRef Sym,
const llvm::APSInt &Int,
+ const llvm::APFloat &Scale,
const llvm::APSInt &Adjustment) {
// Before we do any real work, see if the value can even show up.
APSIntType AdjustmentType(Adjustment);
@@ -606,8 +642,10 @@
return F.getEmptySet();
}
- // Special case for Int == Max. This is always false.
- llvm::APSInt ComparisonVal = AdjustmentType.convert(Int);
+ llvm::APSInt ScInt = rescale(Int, Scale);
+
+ // Special case for ScInt == Max. This is always false.
+ llvm::APSInt ComparisonVal = AdjustmentType.convert(ScInt);
llvm::APSInt Max = AdjustmentType.getMaxValue();
if (ComparisonVal == Max)
return F.getEmptySet();
@@ -622,14 +660,16 @@
ProgramStateRef
RangeConstraintManager::assumeSymGT(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Int,
+ const llvm::APFloat &Scale,
const llvm::APSInt &Adjustment) {
- RangeSet New = getSymGTRange(St, Sym, Int, Adjustment);
+ RangeSet New = getSymGTRange(St, Sym, Int, Scale, Adjustment);
return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New);
}
RangeSet RangeConstraintManager::getSymGERange(ProgramStateRef St,
SymbolRef Sym,
const llvm::APSInt &Int,
+ const llvm::APFloat &Scale,
const llvm::APSInt &Adjustment) {
// Before we do any real work, see if the value can even show up.
APSIntType AdjustmentType(Adjustment);
@@ -642,8 +682,10 @@
return F.getEmptySet();
}
- // Special case for Int == Min. This is always feasible.
- llvm::APSInt ComparisonVal = AdjustmentType.convert(Int);
+ llvm::APSInt ScInt = rescale(Int, Scale);
+
+ // Special case for ScInt == Min. This is always feasible.
+ llvm::APSInt ComparisonVal = AdjustmentType.convert(ScInt);
llvm::APSInt Min = AdjustmentType.getMinValue();
if (ComparisonVal == Min)
return getRange(St, Sym);
@@ -658,14 +700,16 @@
ProgramStateRef
RangeConstraintManager::assumeSymGE(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Int,
+ const llvm::APFloat &Scale,
const llvm::APSInt &Adjustment) {
- RangeSet New = getSymGERange(St, Sym, Int, Adjustment);
+ RangeSet New = getSymGERange(St, Sym, Int, Scale, Adjustment);
return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New);
}
RangeSet RangeConstraintManager::getSymLERange(
llvm::function_ref<RangeSet()> RS,
const llvm::APSInt &Int,
+ const llvm::APFloat &Scale,
const llvm::APSInt &Adjustment) {
// Before we do any real work, see if the value can even show up.
APSIntType AdjustmentType(Adjustment);
@@ -678,8 +722,10 @@
return RS();
}
- // Special case for Int == Max. This is always feasible.
- llvm::APSInt ComparisonVal = AdjustmentType.convert(Int);
+ llvm::APSInt ScInt = rescale(Int, Scale);
+
+ // Special case for ScInt == Max. This is always feasible.
+ llvm::APSInt ComparisonVal = AdjustmentType.convert(ScInt);
llvm::APSInt Max = AdjustmentType.getMaxValue();
if (ComparisonVal == Max)
return RS();
@@ -694,33 +740,38 @@
RangeSet RangeConstraintManager::getSymLERange(ProgramStateRef St,
SymbolRef Sym,
const llvm::APSInt &Int,
+ const llvm::APFloat &Scale,
const llvm::APSInt &Adjustment) {
- return getSymLERange([&] { return getRange(St, Sym); }, Int, Adjustment);
+ return getSymLERange([&] { return getRange(St, Sym); }, Int, Scale,
+ Adjustment);
}
ProgramStateRef
RangeConstraintManager::assumeSymLE(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Int,
+ const llvm::APFloat &Scale,
const llvm::APSInt &Adjustment) {
- RangeSet New = getSymLERange(St, Sym, Int, Adjustment);
+ RangeSet New = getSymLERange(St, Sym, Int, Scale, Adjustment);
return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New);
}
ProgramStateRef RangeConstraintManager::assumeSymWithinInclusiveRange(
ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From,
- const llvm::APSInt &To, const llvm::APSInt &Adjustment) {
- RangeSet New = getSymGERange(State, Sym, From, Adjustment);
+ const llvm::APSInt &To, const llvm::APFloat &Scale,
+ const llvm::APSInt &Adjustment) {
+ RangeSet New = getSymGERange(State, Sym, From, Scale, Adjustment);
if (New.isEmpty())
return nullptr;
- RangeSet Out = getSymLERange([&] { return New; }, To, Adjustment);
+ RangeSet Out = getSymLERange([&] { return New; }, To, Scale, Adjustment);
return Out.isEmpty() ? nullptr : State->set<ConstraintRange>(Sym, Out);
}
ProgramStateRef RangeConstraintManager::assumeSymOutsideInclusiveRange(
ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From,
- const llvm::APSInt &To, const llvm::APSInt &Adjustment) {
- RangeSet RangeLT = getSymLTRange(State, Sym, From, Adjustment);
- RangeSet RangeGT = getSymGTRange(State, Sym, To, Adjustment);
+ const llvm::APSInt &To, const llvm::APFloat &Scale,
+ const llvm::APSInt &Adjustment) {
+ RangeSet RangeLT = getSymLTRange(State, Sym, From, Scale, Adjustment);
+ RangeSet RangeGT = getSymGTRange(State, Sym, To, Scale, Adjustment);
RangeSet New(RangeLT.addRange(F, RangeGT));
return New.isEmpty() ? nullptr : State->set<ConstraintRange>(Sym, New);
}
Index: include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
===================================================================
--- include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
+++ include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
@@ -172,41 +172,50 @@
virtual ProgramStateRef assumeSymNE(ProgramStateRef State, SymbolRef Sym,
const llvm::APSInt &V,
+ const llvm::APFloat &Scale,
const llvm::APSInt &Adjustment) = 0;
virtual ProgramStateRef assumeSymEQ(ProgramStateRef State, SymbolRef Sym,
const llvm::APSInt &V,
+ const llvm::APFloat &Scale,
const llvm::APSInt &Adjustment) = 0;
virtual ProgramStateRef assumeSymLT(ProgramStateRef State, SymbolRef Sym,
const llvm::APSInt &V,
+ const llvm::APFloat &Scale,
const llvm::APSInt &Adjustment) = 0;
virtual ProgramStateRef assumeSymGT(ProgramStateRef State, SymbolRef Sym,
const llvm::APSInt &V,
+ const llvm::APFloat &Scale,
const llvm::APSInt &Adjustment) = 0;
virtual ProgramStateRef assumeSymLE(ProgramStateRef State, SymbolRef Sym,
const llvm::APSInt &V,
+ const llvm::APFloat &Scale,
const llvm::APSInt &Adjustment) = 0;
virtual ProgramStateRef assumeSymGE(ProgramStateRef State, SymbolRef Sym,
const llvm::APSInt &V,
+ const llvm::APFloat &Scale,
const llvm::APSInt &Adjustment) = 0;
virtual ProgramStateRef assumeSymWithinInclusiveRange(
ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From,
- const llvm::APSInt &To, const llvm::APSInt &Adjustment) = 0;
+ const llvm::APSInt &To, const llvm::APFloat &Scale,
+ const llvm::APSInt &Adjustment) = 0;
virtual ProgramStateRef assumeSymOutsideInclusiveRange(
ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From,
- const llvm::APSInt &To, const llvm::APSInt &Adjustment) = 0;
+ const llvm::APSInt &To, const llvm::APFloat &Scale,
+ const llvm::APSInt &Adjustment) = 0;
//===------------------------------------------------------------------===//
// Internal implementation.
//===------------------------------------------------------------------===//
private:
static void computeAdjustment(SymbolRef &Sym, llvm::APSInt &Adjustment);
+ static void computeScale(SymbolRef &Sym, llvm::APFloat &Scale);
};
} // end GR namespace
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits