Skip to content

Commit 867e86a

Browse files
[analyzer][solver] Prevent infeasible states (PR49490)
This patch fixes the situation when our knowledge of disequalities can help us figuring out that some assumption is infeasible, but the solver still produces a state with inconsistent constraints. Additionally, this patch adds a couple of assertions to catch this type of problems easier. Differential Revision: https://reviews.llvm.org/D98341 (cherry picked from commit 6dc1523)
1 parent 3fbbfbc commit 867e86a

File tree

2 files changed

+55
-3
lines changed

2 files changed

+55
-3
lines changed

clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h"
2020
#include "llvm/ADT/FoldingSet.h"
2121
#include "llvm/ADT/ImmutableSet.h"
22+
#include "llvm/ADT/STLExtras.h"
23+
#include "llvm/Support/Compiler.h"
2224
#include "llvm/Support/raw_ostream.h"
2325

2426
using namespace clang;
@@ -1395,12 +1397,23 @@ class RangeConstraintManager : public RangedConstraintManager {
13951397
return EquivalenceClass::merge(getBasicVals(), F, State, LHS, RHS);
13961398
}
13971399

1398-
LLVM_NODISCARD inline ProgramStateRef setConstraint(ProgramStateRef State,
1399-
EquivalenceClass Class,
1400-
RangeSet Constraint) {
1400+
LLVM_NODISCARD LLVM_ATTRIBUTE_UNUSED static bool
1401+
areFeasible(ConstraintRangeTy Constraints) {
1402+
return llvm::none_of(
1403+
Constraints,
1404+
[](const std::pair<EquivalenceClass, RangeSet> &ClassConstraint) {
1405+
return ClassConstraint.second.isEmpty();
1406+
});
1407+
}
1408+
1409+
LLVM_NODISCARD ProgramStateRef setConstraint(ProgramStateRef State,
1410+
EquivalenceClass Class,
1411+
RangeSet Constraint) {
14011412
ConstraintRangeTy Constraints = State->get<ConstraintRange>();
14021413
ConstraintRangeTy::Factory &CF = State->get_context<ConstraintRange>();
14031414

1415+
assert(!Constraint.isEmpty() && "New constraint should not be empty");
1416+
14041417
// Add new constraint.
14051418
Constraints = CF.add(Constraints, Class, Constraint);
14061419

@@ -1413,9 +1426,18 @@ class RangeConstraintManager : public RangedConstraintManager {
14131426
for (EquivalenceClass DisequalClass : Class.getDisequalClasses(State)) {
14141427
RangeSet UpdatedConstraint =
14151428
getRange(State, DisequalClass).Delete(getBasicVals(), F, *Point);
1429+
1430+
// If we end up with at least one of the disequal classes to be
1431+
// constrainted with an empty range-set, the state is infeasible.
1432+
if (UpdatedConstraint.isEmpty())
1433+
return nullptr;
1434+
14161435
Constraints = CF.add(Constraints, DisequalClass, UpdatedConstraint);
14171436
}
14181437

1438+
assert(areFeasible(Constraints) && "Constraint manager shouldn't produce "
1439+
"a state with infeasible constraints");
1440+
14191441
return State->set<ConstraintRange>(Constraints);
14201442
}
14211443

clang/test/Analysis/PR49490.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// RUN: %clang_analyze_cc1 -w -analyzer-checker=core -verify %s
2+
3+
// expected-no-diagnostics
4+
5+
struct toggle {
6+
bool value;
7+
};
8+
9+
toggle global_toggle;
10+
toggle get_global_toggle() { return global_toggle; }
11+
12+
int oob_access();
13+
14+
bool compare(toggle one, bool other) {
15+
if (one.value != other)
16+
return true;
17+
18+
if (one.value)
19+
oob_access();
20+
return true;
21+
}
22+
23+
bool coin();
24+
25+
void bar() {
26+
bool left = coin();
27+
bool right = coin();
28+
for (;;)
29+
compare(get_global_toggle(), left) && compare(get_global_toggle(), right);
30+
}

0 commit comments

Comments
 (0)