Skip to content

Commit 77660ee

Browse files
author
Adam Balogh
committedJun 28, 2018
[Analyzer] Constraint Manager Negates Difference
If range [m .. n] is stored for symbolic expression A - B, then we can deduce the range for B - A which is [-n .. -m]. This is only true for signed types, unless the range is [0 .. 0]. Differential Revision: https://reviews.llvm.org/D35110 llvm-svn: 335814
1 parent 17a098d commit 77660ee

File tree

4 files changed

+168
-24
lines changed

4 files changed

+168
-24
lines changed
 

‎clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h

+2
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ class RangeSet {
115115
RangeSet Intersect(BasicValueFactory &BV, Factory &F, llvm::APSInt Lower,
116116
llvm::APSInt Upper) const;
117117

118+
RangeSet Negate(BasicValueFactory &BV, Factory &F) const;
119+
118120
void print(raw_ostream &os) const;
119121

120122
bool operator==(const RangeSet &other) const {

‎clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp

+68-1
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,38 @@ RangeSet RangeSet::Intersect(BasicValueFactory &BV, Factory &F,
174174
return newRanges;
175175
}
176176

177+
// Turn all [A, B] ranges to [-B, -A]. Ranges [MIN, B] are turned to range set
178+
// [MIN, MIN] U [-B, MAX], when MIN and MAX are the minimal and the maximal
179+
// signed values of the type.
180+
RangeSet RangeSet::Negate(BasicValueFactory &BV, Factory &F) const {
181+
PrimRangeSet newRanges = F.getEmptySet();
182+
183+
for (iterator i = begin(), e = end(); i != e; ++i) {
184+
const llvm::APSInt &from = i->From(), &to = i->To();
185+
const llvm::APSInt &newTo = (from.isMinSignedValue() ?
186+
BV.getMaxValue(from) :
187+
BV.getValue(- from));
188+
if (to.isMaxSignedValue() && !newRanges.isEmpty() &&
189+
newRanges.begin()->From().isMinSignedValue()) {
190+
assert(newRanges.begin()->To().isMinSignedValue() &&
191+
"Ranges should not overlap");
192+
assert(!from.isMinSignedValue() && "Ranges should not overlap");
193+
const llvm::APSInt &newFrom = newRanges.begin()->From();
194+
newRanges =
195+
F.add(F.remove(newRanges, *newRanges.begin()), Range(newFrom, newTo));
196+
} else if (!to.isMinSignedValue()) {
197+
const llvm::APSInt &newFrom = BV.getValue(- to);
198+
newRanges = F.add(newRanges, Range(newFrom, newTo));
199+
}
200+
if (from.isMinSignedValue()) {
201+
newRanges = F.add(newRanges, Range(BV.getMinValue(from),
202+
BV.getMinValue(from)));
203+
}
204+
}
205+
206+
return newRanges;
207+
}
208+
177209
void RangeSet::print(raw_ostream &os) const {
178210
bool isFirst = true;
179211
os << "{ ";
@@ -252,6 +284,8 @@ class RangeConstraintManager : public RangedConstraintManager {
252284
RangeSet::Factory F;
253285

254286
RangeSet getRange(ProgramStateRef State, SymbolRef Sym);
287+
const RangeSet* getRangeForMinusSymbol(ProgramStateRef State,
288+
SymbolRef Sym);
255289

256290
RangeSet getSymLTRange(ProgramStateRef St, SymbolRef Sym,
257291
const llvm::APSInt &Int,
@@ -268,6 +302,7 @@ class RangeConstraintManager : public RangedConstraintManager {
268302
RangeSet getSymGERange(ProgramStateRef St, SymbolRef Sym,
269303
const llvm::APSInt &Int,
270304
const llvm::APSInt &Adjustment);
305+
271306
};
272307

273308
} // end anonymous namespace
@@ -423,9 +458,15 @@ RangeSet RangeConstraintManager::getRange(ProgramStateRef State,
423458
if (ConstraintRangeTy::data_type *V = State->get<ConstraintRange>(Sym))
424459
return *V;
425460

461+
BasicValueFactory &BV = getBasicVals();
462+
463+
// If Sym is a difference of symbols A - B, then maybe we have range set
464+
// stored for B - A.
465+
if (const RangeSet *R = getRangeForMinusSymbol(State, Sym))
466+
return R->Negate(BV, F);
467+
426468
// Lazily generate a new RangeSet representing all possible values for the
427469
// given symbol type.
428-
BasicValueFactory &BV = getBasicVals();
429470
QualType T = Sym->getType();
430471

431472
RangeSet Result(F, BV.getMinValue(T), BV.getMaxValue(T));
@@ -441,6 +482,32 @@ RangeSet RangeConstraintManager::getRange(ProgramStateRef State,
441482
return Result;
442483
}
443484

485+
// FIXME: Once SValBuilder supports unary minus, we should use SValBuilder to
486+
// obtain the negated symbolic expression instead of constructing the
487+
// symbol manually. This will allow us to support finding ranges of not
488+
// only negated SymSymExpr-type expressions, but also of other, simpler
489+
// expressions which we currently do not know how to negate.
490+
const RangeSet*
491+
RangeConstraintManager::getRangeForMinusSymbol(ProgramStateRef State,
492+
SymbolRef Sym) {
493+
if (const SymSymExpr *SSE = dyn_cast<SymSymExpr>(Sym)) {
494+
if (SSE->getOpcode() == BO_Sub) {
495+
QualType T = Sym->getType();
496+
SymbolManager &SymMgr = State->getSymbolManager();
497+
SymbolRef negSym = SymMgr.getSymSymExpr(SSE->getRHS(), BO_Sub,
498+
SSE->getLHS(), T);
499+
if (const RangeSet *negV = State->get<ConstraintRange>(negSym)) {
500+
// Unsigned range set cannot be negated, unless it is [0, 0].
501+
if ((negV->getConcreteValue() &&
502+
(*negV->getConcreteValue() == 0)) ||
503+
T->isSignedIntegerOrEnumerationType())
504+
return negV;
505+
}
506+
}
507+
}
508+
return nullptr;
509+
}
510+
444511
//===------------------------------------------------------------------------===
445512
// assumeSymX methods: protected interface for RangeConstraintManager.
446513
//===------------------------------------------------------------------------===/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
// RUN: %clang_analyze_cc1 -analyzer-checker=debug.ExprInspection,core.builtin -analyzer-config aggressive-relational-comparison-simplification=true -verify %s
2+
3+
void clang_analyzer_eval(int);
4+
5+
void exit(int);
6+
7+
#define UINT_MAX (~0U)
8+
#define INT_MAX (UINT_MAX & (UINT_MAX >> 1))
9+
#define INT_MIN (UINT_MAX & ~(UINT_MAX >> 1))
10+
11+
extern void __assert_fail (__const char *__assertion, __const char *__file,
12+
unsigned int __line, __const char *__function)
13+
__attribute__ ((__noreturn__));
14+
#define assert(expr) \
15+
((expr) ? (void)(0) : __assert_fail (#expr, __FILE__, __LINE__, __func__))
16+
17+
void assert_in_range(int x) {
18+
assert(x <= ((int)INT_MAX / 4));
19+
assert(x >= -(((int)INT_MAX) / 4));
20+
}
21+
22+
void assert_in_wide_range(int x) {
23+
assert(x <= ((int)INT_MAX / 2));
24+
assert(x >= -(((int)INT_MAX) / 2));
25+
}
26+
27+
void assert_in_range_2(int m, int n) {
28+
assert_in_range(m);
29+
assert_in_range(n);
30+
}
31+
32+
void equal(int m, int n) {
33+
assert_in_range_2(m, n);
34+
if (m != n)
35+
return;
36+
assert_in_wide_range(m - n);
37+
clang_analyzer_eval(n == m); // expected-warning{{TRUE}}
38+
}
39+
40+
void non_equal(int m, int n) {
41+
assert_in_range_2(m, n);
42+
if (m == n)
43+
return;
44+
assert_in_wide_range(m - n);
45+
clang_analyzer_eval(n != m); // expected-warning{{TRUE}}
46+
}
47+
48+
void less_or_equal(int m, int n) {
49+
assert_in_range_2(m, n);
50+
if (m < n)
51+
return;
52+
assert_in_wide_range(m - n);
53+
clang_analyzer_eval(n <= m); // expected-warning{{TRUE}}
54+
}
55+
56+
void less(int m, int n) {
57+
assert_in_range_2(m, n);
58+
if (m <= n)
59+
return;
60+
assert_in_wide_range(m - n);
61+
clang_analyzer_eval(n < m); // expected-warning{{TRUE}}
62+
}
63+
64+
void greater_or_equal(int m, int n) {
65+
assert_in_range_2(m, n);
66+
if (m > n)
67+
return;
68+
assert_in_wide_range(m - n);
69+
clang_analyzer_eval(n >= m); // expected-warning{{TRUE}}
70+
}
71+
72+
void greater(int m, int n) {
73+
assert_in_range_2(m, n);
74+
if (m >= n)
75+
return;
76+
assert_in_wide_range(m - n);
77+
clang_analyzer_eval(n > m); // expected-warning{{TRUE}}
78+
}
79+
80+
void negate_positive_range(int m, int n) {
81+
if (m - n <= 0)
82+
return;
83+
clang_analyzer_eval(n - m < 0); // expected-warning{{TRUE}}
84+
clang_analyzer_eval(n - m > INT_MIN); // expected-warning{{TRUE}}
85+
clang_analyzer_eval(n - m == INT_MIN); // expected-warning{{FALSE}}
86+
}
87+
88+
void negate_int_min(int m, int n) {
89+
if (m - n != INT_MIN)
90+
return;
91+
clang_analyzer_eval(n - m == INT_MIN); // expected-warning{{TRUE}}
92+
}
93+
94+
void negate_mixed(int m, int n) {
95+
if (m -n > INT_MIN && m - n <= 0)
96+
return;
97+
clang_analyzer_eval(n - m <= 0); // expected-warning{{TRUE}}
98+
}

‎clang/test/Analysis/ptr-arith.c

-23
Original file line numberDiff line numberDiff line change
@@ -265,49 +265,26 @@ void size_implies_comparison(int *lhs, int *rhs) {
265265
clang_analyzer_eval((rhs - lhs) > 0); // expected-warning{{TRUE}}
266266
}
267267

268-
//-------------------------------
269-
// False positives
270-
//-------------------------------
271-
272268
void zero_implies_reversed_equal(int *lhs, int *rhs) {
273269
clang_analyzer_eval((rhs - lhs) == 0); // expected-warning{{UNKNOWN}}
274270
if ((rhs - lhs) == 0) {
275-
#ifdef ANALYZER_CM_Z3
276271
clang_analyzer_eval(rhs != lhs); // expected-warning{{FALSE}}
277272
clang_analyzer_eval(rhs == lhs); // expected-warning{{TRUE}}
278-
#else
279-
clang_analyzer_eval(rhs != lhs); // expected-warning{{UNKNOWN}}
280-
clang_analyzer_eval(rhs == lhs); // expected-warning{{UNKNOWN}}
281-
#endif
282273
return;
283274
}
284275
clang_analyzer_eval((rhs - lhs) == 0); // expected-warning{{FALSE}}
285-
#ifdef ANALYZER_CM_Z3
286276
clang_analyzer_eval(rhs == lhs); // expected-warning{{FALSE}}
287277
clang_analyzer_eval(rhs != lhs); // expected-warning{{TRUE}}
288-
#else
289-
clang_analyzer_eval(rhs == lhs); // expected-warning{{UNKNOWN}}
290-
clang_analyzer_eval(rhs != lhs); // expected-warning{{UNKNOWN}}
291-
#endif
292278
}
293279

294280
void canonical_equal(int *lhs, int *rhs) {
295281
clang_analyzer_eval(lhs == rhs); // expected-warning{{UNKNOWN}}
296282
if (lhs == rhs) {
297-
#ifdef ANALYZER_CM_Z3
298283
clang_analyzer_eval(rhs == lhs); // expected-warning{{TRUE}}
299-
#else
300-
clang_analyzer_eval(rhs == lhs); // expected-warning{{UNKNOWN}}
301-
#endif
302284
return;
303285
}
304286
clang_analyzer_eval(lhs == rhs); // expected-warning{{FALSE}}
305-
306-
#ifdef ANALYZER_CM_Z3
307287
clang_analyzer_eval(rhs == lhs); // expected-warning{{FALSE}}
308-
#else
309-
clang_analyzer_eval(rhs == lhs); // expected-warning{{UNKNOWN}}
310-
#endif
311288
}
312289

313290
void compare_element_region_and_base(int *p) {

0 commit comments

Comments
 (0)
Please sign in to comment.