diff options
Diffstat (limited to 'lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp | 102 |
1 files changed, 94 insertions, 8 deletions
diff --git a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp index 28b43dd566d5..82ce8b45fe78 100644 --- a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp +++ b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp @@ -14,6 +14,7 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" #include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h" using namespace clang; using namespace ento; @@ -44,6 +45,10 @@ public: /// (integer) value, that value is returned. Otherwise, returns NULL. const llvm::APSInt *getKnownValue(ProgramStateRef state, SVal V) override; + /// Recursively descends into symbolic expressions and replaces symbols + /// with their known values (in the sense of the getKnownValue() method). + SVal simplifySVal(ProgramStateRef State, SVal V) override; + SVal MakeSymIntVal(const SymExpr *LHS, BinaryOperator::Opcode op, const llvm::APSInt &RHS, QualType resultTy); }; @@ -362,6 +367,9 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state, resultTy); case nonloc::ConcreteIntKind: { // Transform the integer into a location and compare. + // FIXME: This only makes sense for comparisons. If we want to, say, + // add 1 to a LocAsInteger, we'd better unpack the Loc and add to it, + // then pack it back into a LocAsInteger. llvm::APSInt i = rhs.castAs<nonloc::ConcreteInt>().getValue(); BasicVals.getAPSIntType(Context.VoidPtrTy).apply(i); return evalBinOpLL(state, op, lhsL, makeLoc(i), resultTy); @@ -534,11 +542,12 @@ 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. - ConstraintManager &CMgr = state->getConstraintManager(); - if (const llvm::APSInt *Constant = CMgr.getSymVal(state, Sym)) { - lhs = nonloc::ConcreteInt(*Constant); - continue; - } + 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)) @@ -941,20 +950,26 @@ SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state, if (const MemRegion *region = lhs.getAsRegion()) { rhs = convertToArrayIndex(rhs).castAs<NonLoc>(); SVal index = UnknownVal(); - const MemRegion *superR = nullptr; + const SubRegion *superR = nullptr; + // We need to know the type of the pointer in order to add an integer to it. + // Depending on the type, different amount of bytes is added. QualType elementType; if (const ElementRegion *elemReg = dyn_cast<ElementRegion>(region)) { assert(op == BO_Add || op == BO_Sub); index = evalBinOpNN(state, op, elemReg->getIndex(), rhs, getArrayIndexType()); - superR = elemReg->getSuperRegion(); + superR = cast<SubRegion>(elemReg->getSuperRegion()); elementType = elemReg->getElementType(); } else if (isa<SubRegion>(region)) { assert(op == BO_Add || op == BO_Sub); index = (op == BO_Add) ? rhs : evalMinus(rhs); - superR = region; + superR = cast<SubRegion>(region); + // TODO: Is this actually reliable? Maybe improving our MemRegion + // hierarchy to provide typed regions for all non-void pointers would be + // better. For instance, we cannot extend this towards LocAsInteger + // operations, where result type of the expression is integer. if (resultTy->isAnyPointerType()) elementType = resultTy->getPointeeType(); } @@ -984,3 +999,74 @@ const llvm::APSInt *SimpleSValBuilder::getKnownValue(ProgramStateRef state, // FIXME: Add support for SymExprs. return nullptr; } + +SVal SimpleSValBuilder::simplifySVal(ProgramStateRef State, SVal V) { + // For now, this function tries to constant-fold symbols inside a + // nonloc::SymbolVal, and does nothing else. More simplifications should + // be possible, such as constant-folding an index in an ElementRegion. + + class Simplifier : public FullSValVisitor<Simplifier, SVal> { + ProgramStateRef State; + SValBuilder &SVB; + + public: + Simplifier(ProgramStateRef State) + : State(State), SVB(State->getStateManager().getSValBuilder()) {} + + SVal VisitSymbolData(const SymbolData *S) { + if (const llvm::APSInt *I = + SVB.getKnownValue(State, nonloc::SymbolVal(S))) + return Loc::isLocType(S->getType()) ? (SVal)SVB.makeIntLocVal(*I) + : (SVal)SVB.makeIntVal(*I); + return nonloc::SymbolVal(S); + } + + // TODO: Support SymbolCast. Support IntSymExpr when/if we actually + // start producing them. + + SVal VisitSymIntExpr(const SymIntExpr *S) { + SVal LHS = Visit(S->getLHS()); + SVal RHS; + // By looking at the APSInt in the right-hand side of S, we cannot + // figure out if it should be treated as a Loc or as a NonLoc. + // So make our guess by recalling that we cannot multiply pointers + // or compare a pointer to an integer. + if (Loc::isLocType(S->getLHS()->getType()) && + BinaryOperator::isComparisonOp(S->getOpcode())) { + // The usual conversion of $sym to &SymRegion{$sym}, as they have + // the same meaning for Loc-type symbols, but the latter form + // is preferred in SVal computations for being Loc itself. + if (SymbolRef Sym = LHS.getAsSymbol()) { + assert(Loc::isLocType(Sym->getType())); + LHS = SVB.makeLoc(Sym); + } + RHS = SVB.makeIntLocVal(S->getRHS()); + } else { + RHS = SVB.makeIntVal(S->getRHS()); + } + return SVB.evalBinOp(State, S->getOpcode(), LHS, RHS, S->getType()); + } + + SVal VisitSymSymExpr(const SymSymExpr *S) { + SVal LHS = Visit(S->getLHS()); + SVal RHS = Visit(S->getRHS()); + return SVB.evalBinOp(State, S->getOpcode(), LHS, RHS, S->getType()); + } + + SVal VisitSymExpr(SymbolRef S) { return nonloc::SymbolVal(S); } + + SVal VisitMemRegion(const MemRegion *R) { return loc::MemRegionVal(R); } + + SVal VisitNonLocSymbolVal(nonloc::SymbolVal V) { + // Simplification is much more costly than computing complexity. + // For high complexity, it may be not worth it. + if (V.getSymbol()->computeComplexity() > 100) + return V; + return Visit(V.getSymbol()); + } + + SVal VisitSVal(SVal V) { return V; } + }; + + return Simplifier(State).Visit(V); +} |