diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2021-12-02 21:02:54 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2021-12-02 21:02:54 +0000 |
| commit | f65dcba83ce5035ab88a85fe17628b447eb56e1b (patch) | |
| tree | 35f37bb72b3cfc6060193e66c76ee7c9478969b0 /clang/lib/StaticAnalyzer | |
| parent | 846a2208a8ab099f595fe7e8b2e6d54a7b5e67fb (diff) | |
Diffstat (limited to 'clang/lib/StaticAnalyzer')
4 files changed, 102 insertions, 27 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp index bc939d252800..d57bab154b61 100644 --- a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp @@ -686,8 +686,8 @@ SwitchNodeBuilder::generateDefaultCaseNode(ProgramStateRef St, assert(Src->succ_rbegin() != Src->succ_rend()); CFGBlock *DefaultBlock = *Src->succ_rbegin(); - // Sanity check for default blocks that are unreachable and not caught - // by earlier stages. + // Basic correctness check for default blocks that are unreachable and not + // caught by earlier stages. if (!DefaultBlock) return nullptr; diff --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp index 74403a160b8e..23c67c64f975 100644 --- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp @@ -2191,6 +2191,42 @@ LLVM_NODISCARD ProgramStateRef reAssume(ProgramStateRef State, Constraint->getMaxValue(), true); } +// Simplify the given symbol with the help of the SValBuilder. In +// SValBuilder::symplifySval, we traverse the symbol tree and query the +// constraint values for the sub-trees and if a value is a constant we do the +// constant folding. Compound symbols might collapse to simpler symbol tree +// that is still possible to further simplify. Thus, we do the simplification on +// a new symbol tree until we reach the simplest form, i.e. the fixpoint. +// +// Consider the following symbol `(b * b) * b * b` which has this tree: +// * +// / \ +// * b +// / \ +// / b +// (b * b) +// Now, if the `b * b == 1` new constraint is added then during the first +// iteration we have the following transformations: +// * * +// / \ / \ +// * b --> b b +// / \ +// / b +// 1 +// We need another iteration to reach the final result `1`. +LLVM_NODISCARD +static SVal simplifyUntilFixpoint(SValBuilder &SVB, ProgramStateRef State, + const SymbolRef Sym) { + SVal Val = SVB.makeSymbolVal(Sym); + SVal SimplifiedVal = SVB.simplifySVal(State, Val); + // Do the simplification until we can. + while (SimplifiedVal != Val) { + Val = SimplifiedVal; + SimplifiedVal = SVB.simplifySVal(State, Val); + } + return SimplifiedVal; +} + // Iterate over all symbols and try to simplify them. Once a symbol is // simplified then we check if we can merge the simplified symbol's equivalence // class to this class. This way, we simplify not just the symbols but the @@ -2202,7 +2238,8 @@ EquivalenceClass::simplify(SValBuilder &SVB, RangeSet::Factory &F, SymbolSet ClassMembers = Class.getClassMembers(State); for (const SymbolRef &MemberSym : ClassMembers) { - const SVal SimplifiedMemberVal = simplifyToSVal(State, MemberSym); + const SVal SimplifiedMemberVal = + simplifyUntilFixpoint(SVB, State, MemberSym); const SymbolRef SimplifiedMemberSym = SimplifiedMemberVal.getAsSymbol(); // The symbol is collapsed to a constant, check if the current State is diff --git a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp index 681a1f64eadc..4ca35dd06ae5 100644 --- a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp +++ b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp @@ -372,6 +372,15 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state, NonLoc InputLHS = lhs; NonLoc InputRHS = rhs; + // Constraints may have changed since the creation of a bound SVal. Check if + // the values can be simplified based on those new constraints. + SVal simplifiedLhs = simplifySVal(state, lhs); + SVal simplifiedRhs = simplifySVal(state, rhs); + if (auto simplifiedLhsAsNonLoc = simplifiedLhs.getAs<NonLoc>()) + lhs = *simplifiedLhsAsNonLoc; + if (auto simplifiedRhsAsNonLoc = simplifiedRhs.getAs<NonLoc>()) + rhs = *simplifiedRhsAsNonLoc; + // Handle trivial case where left-side and right-side are the same. if (lhs == rhs) switch (op) { @@ -619,16 +628,6 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state, } } - // Does the symbolic expression simplify to a constant? - // If so, "fold" the constant by setting 'lhs' to a ConcreteInt - // and try again. - SVal simplifiedLhs = simplifySVal(state, lhs); - if (simplifiedLhs != lhs) - if (auto simplifiedLhsAsNonLoc = simplifiedLhs.getAs<NonLoc>()) { - lhs = *simplifiedLhsAsNonLoc; - continue; - } - // Is the RHS a constant? if (const llvm::APSInt *RHSValue = getKnownValue(state, rhs)) return MakeSymIntVal(Sym, op, *RHSValue, resultTy); @@ -1103,7 +1102,6 @@ const llvm::APSInt *SimpleSValBuilder::getKnownValue(ProgramStateRef state, if (SymbolRef Sym = V.getAsSymbol()) return state->getConstraintManager().getSymVal(state, Sym); - // FIXME: Add support for SymExprs. return nullptr; } @@ -1135,6 +1133,24 @@ SVal SimpleSValBuilder::simplifySVal(ProgramStateRef State, SVal V) { return cache(Sym, SVB.makeSymbolVal(Sym)); } + // Return the known const value for the Sym if available, or return Undef + // otherwise. + SVal getConst(SymbolRef Sym) { + const llvm::APSInt *Const = + State->getConstraintManager().getSymVal(State, Sym); + if (Const) + return Loc::isLocType(Sym->getType()) ? (SVal)SVB.makeIntLocVal(*Const) + : (SVal)SVB.makeIntVal(*Const); + return UndefinedVal(); + } + + SVal getConstOrVisit(SymbolRef Sym) { + const SVal Ret = getConst(Sym); + if (Ret.isUndef()) + return Visit(Sym); + return Ret; + } + public: Simplifier(ProgramStateRef State) : State(State), SVB(State->getStateManager().getSValBuilder()) {} @@ -1148,15 +1164,14 @@ SVal SimpleSValBuilder::simplifySVal(ProgramStateRef State, SVal V) { return SVB.makeSymbolVal(S); } - // TODO: Support SymbolCast. Support IntSymExpr when/if we actually - // start producing them. + // TODO: Support SymbolCast. SVal VisitSymIntExpr(const SymIntExpr *S) { auto I = Cached.find(S); if (I != Cached.end()) return I->second; - SVal LHS = Visit(S->getLHS()); + SVal LHS = getConstOrVisit(S->getLHS()); if (isUnchanged(S->getLHS(), LHS)) return skip(S); @@ -1183,6 +1198,20 @@ SVal SimpleSValBuilder::simplifySVal(ProgramStateRef State, SVal V) { S, SVB.evalBinOp(State, S->getOpcode(), LHS, RHS, S->getType())); } + SVal VisitIntSymExpr(const IntSymExpr *S) { + auto I = Cached.find(S); + if (I != Cached.end()) + return I->second; + + SVal RHS = getConstOrVisit(S->getRHS()); + if (isUnchanged(S->getRHS(), RHS)) + return skip(S); + + SVal LHS = SVB.makeIntVal(S->getLHS()); + return cache( + S, SVB.evalBinOp(State, S->getOpcode(), LHS, RHS, S->getType())); + } + SVal VisitSymSymExpr(const SymSymExpr *S) { auto I = Cached.find(S); if (I != Cached.end()) @@ -1196,8 +1225,9 @@ SVal SimpleSValBuilder::simplifySVal(ProgramStateRef State, SVal V) { Loc::isLocType(S->getRHS()->getType())) return skip(S); - SVal LHS = Visit(S->getLHS()); - SVal RHS = Visit(S->getRHS()); + SVal LHS = getConstOrVisit(S->getLHS()); + SVal RHS = getConstOrVisit(S->getRHS()); + if (isUnchanged(S->getLHS(), LHS) && isUnchanged(S->getRHS(), RHS)) return skip(S); diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index 31de49033ac2..f692c68045ee 100644 --- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -591,16 +591,24 @@ AnalysisConsumer::getModeForDecl(Decl *D, AnalysisMode Mode) { // - Main source file: run both path-sensitive and non-path-sensitive checks. // - Header files: run non-path-sensitive checks only. // - System headers: don't run any checks. - SourceManager &SM = Ctx->getSourceManager(); - const Stmt *Body = D->getBody(); - SourceLocation SL = Body ? Body->getBeginLoc() : D->getLocation(); - SL = SM.getExpansionLoc(SL); + if (Opts->AnalyzeAll) + return Mode; - if (!Opts->AnalyzeAll && !Mgr->isInCodeFile(SL)) { - if (SL.isInvalid() || SM.isInSystemHeader(SL)) - return AM_None; + const SourceManager &SM = Ctx->getSourceManager(); + + const SourceLocation Loc = [&SM](Decl *D) -> SourceLocation { + const Stmt *Body = D->getBody(); + SourceLocation SL = Body ? Body->getBeginLoc() : D->getLocation(); + return SM.getExpansionLoc(SL); + }(D); + + // Ignore system headers. + if (Loc.isInvalid() || SM.isInSystemHeader(Loc)) + return AM_None; + + // Disable path sensitive analysis in user-headers. + if (!Mgr->isInCodeFile(Loc)) return Mode & ~AM_Path; - } return Mode; } |
