diff options
author | Ted Kremenek <kremenek@apple.com> | 2009-06-26 00:05:51 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2009-06-26 00:05:51 +0000 |
commit | 6c07bdba93b095b66e2c8c82dd5ed458fa8285ea (patch) | |
tree | b0c2776d4e55e3a6ab919bf1052c7a13a6a43274 | |
parent | 72b60e35600f5789056f73eca35713a1b83b6594 (diff) |
Introduce a new concept to the static analyzer: SValuator.
GRTransferFuncs had the conflated role of both constructing SVals (symbolic
expressions) as well as handling checker-specific logic. Now SValuator has the
role of constructing SVals from expressions and GRTransferFuncs just handles
checker-specific logic. The motivation is by separating these two concepts we
will be able to much more easily create richer constraint-generating logic
without coupling it to the main checker transfer function logic.
We now have one implementation of SValuator: SimpleSValuator.
SimpleSValuator is essentially the SVal-related logic that was in GRSimpleVals
(which is removed in this patch). This includes the logic for EvalBinOp,
EvalCast, etc. Because SValuator has a narrower role than the old
GRTransferFuncs, the interfaces are much simpler, and so is the implementation
of SimpleSValuator compared to GRSimpleVals. I also did a line-by-line review of
SVal-related logic in GRSimpleVals and cleaned it up while moving it over to
SimpleSValuator.
As a consequence of removing GRSimpleVals, there is no longer a
'-checker-simple' option. The '-checker-cfref' did everything that option did
but also ran the retain/release checker. Of course a user may not always wish to
run the retain/release checker, nor do we wish core analysis logic buried in the
checker-specific logic. The next step is to refactor the logic in CFRefCount.cpp
to separate out these pieces into the core analysis engine.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@74229 91177308-0d34-0410-b5e6-96231b3b80d8
32 files changed, 77 insertions, 617 deletions
diff --git a/include/clang/Analysis/LocalCheckers.h b/include/clang/Analysis/LocalCheckers.h index 23610f9a2d..9ff3f52f89 100644 --- a/include/clang/Analysis/LocalCheckers.h +++ b/include/clang/Analysis/LocalCheckers.h @@ -37,7 +37,6 @@ void CheckDeadStores(LiveVariables& L, BugReporter& BR); void CheckUninitializedValues(CFG& cfg, ASTContext& Ctx, Diagnostic& Diags, bool FullUninitTaint=false); -GRTransferFuncs* MakeGRSimpleValsTF(); GRTransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled, const LangOptions& lopts); diff --git a/include/clang/Analysis/PathSensitive/GRExprEngine.h b/include/clang/Analysis/PathSensitive/GRExprEngine.h index 5db666c4b8..f05bc680a7 100644 --- a/include/clang/Analysis/PathSensitive/GRExprEngine.h +++ b/include/clang/Analysis/PathSensitive/GRExprEngine.h @@ -20,6 +20,7 @@ #include "clang/Analysis/PathSensitive/GRState.h" #include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h" #include "clang/Analysis/PathSensitive/GRTransferFuncs.h" +#include "clang/Analysis/PathSensitive/SValuator.h" #include "clang/Analysis/PathSensitive/BugReporter.h" #include "clang/AST/Type.h" #include "clang/AST/ExprObjC.h" @@ -67,6 +68,9 @@ protected: /// ValMgr - Object that manages/creates SVals. ValueManager &ValMgr; + /// SVator - SValuator object that creates SVals from expressions. + llvm::OwningPtr<SValuator> SVator; + /// EntryNode - The immediate predecessor node. NodeTy* EntryNode; @@ -603,41 +607,32 @@ protected: return X; if (isa<Loc>(X)) - return getTF().EvalCast(*this, cast<Loc>(X), CastT); + return SVator->EvalCast(cast<Loc>(X), CastT); else - return getTF().EvalCast(*this, cast<NonLoc>(X), CastT); + return SVator->EvalCast(cast<NonLoc>(X), CastT); } - SVal EvalMinus(UnaryOperator* U, SVal X) { - return X.isValid() ? getTF().EvalMinus(*this, U, cast<NonLoc>(X)) : X; + SVal EvalMinus(SVal X) { + return X.isValid() ? SVator->EvalMinus(cast<NonLoc>(X)) : X; } SVal EvalComplement(SVal X) { - return X.isValid() ? getTF().EvalComplement(*this, cast<NonLoc>(X)) : X; + return X.isValid() ? SVator->EvalComplement(cast<NonLoc>(X)) : X; } public: - SVal EvalBinOp(BinaryOperator::Opcode Op, NonLoc L, NonLoc R, QualType T) { - return R.isValid() ? getTF().DetermEvalBinOpNN(*this, Op, L, R, T) - : R; + SVal EvalBinOp(BinaryOperator::Opcode op, NonLoc L, NonLoc R, QualType T) { + return SVator->EvalBinOpNN(op, L, R, T); } - SVal EvalBinOp(BinaryOperator::Opcode Op, NonLoc L, SVal R, QualType T) { - return R.isValid() ? getTF().DetermEvalBinOpNN(*this, Op, L, - cast<NonLoc>(R), T) : R; + SVal EvalBinOp(BinaryOperator::Opcode op, NonLoc L, SVal R, QualType T) { + return R.isValid() ? SVator->EvalBinOpNN(op, L, cast<NonLoc>(R), T) : R; } - void EvalBinOp(ExplodedNodeSet<GRState>& Dst, Expr* Ex, - BinaryOperator::Opcode Op, NonLoc L, NonLoc R, - ExplodedNode<GRState>* Pred, QualType T); - - void EvalBinOp(GRStateSet& OStates, const GRState* St, Expr* Ex, - BinaryOperator::Opcode Op, NonLoc L, NonLoc R, QualType T); - - SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode Op, SVal L,SVal R, - QualType T); - + SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode op, + SVal lhs, SVal rhs, QualType T); + protected: void EvalCall(NodeSet& Dst, CallExpr* CE, SVal L, NodeTy* Pred); diff --git a/include/clang/Analysis/PathSensitive/GRTransferFuncs.h b/include/clang/Analysis/PathSensitive/GRTransferFuncs.h index c2f8f5aae0..db23f81e2d 100644 --- a/include/clang/Analysis/PathSensitive/GRTransferFuncs.h +++ b/include/clang/Analysis/PathSensitive/GRTransferFuncs.h @@ -22,20 +22,12 @@ namespace clang { - class GRExprEngine; - class BugReporter; - class ObjCMessageExpr; - class GRStmtNodeBuilderRef; +class GRExprEngine; +class BugReporter; +class ObjCMessageExpr; +class GRStmtNodeBuilderRef; class GRTransferFuncs { - friend class GRExprEngine; -protected: - virtual SVal DetermEvalBinOpNN(GRExprEngine& Eng, - BinaryOperator::Opcode Op, - NonLoc L, NonLoc R, QualType T) { - return UnknownVal(); - } - public: GRTransferFuncs() {} virtual ~GRTransferFuncs() {} @@ -43,33 +35,7 @@ public: virtual void RegisterPrinters(std::vector<GRState::Printer*>& Printers) {} virtual void RegisterChecks(BugReporter& BR) {} - // Casts. - - virtual SVal EvalCast(GRExprEngine& Engine, NonLoc V, QualType CastT) =0; - virtual SVal EvalCast(GRExprEngine& Engine, Loc V, QualType CastT) = 0; - - // Unary Operators. - - virtual SVal EvalMinus(GRExprEngine& Engine, UnaryOperator* U, NonLoc X) = 0; - - virtual SVal EvalComplement(GRExprEngine& Engine, NonLoc X) = 0; - // Binary Operators. - // FIXME: We're moving back towards using GREXprEngine directly. No need - // for OStates - virtual void EvalBinOpNN(GRStateSet& OStates, GRExprEngine& Eng, - const GRState* St, Expr* Ex, - BinaryOperator::Opcode Op, NonLoc L, NonLoc R, - QualType T); - - virtual SVal EvalBinOp(GRExprEngine& Engine, BinaryOperator::Opcode Op, - Loc L, Loc R) = 0; - - // Pointer arithmetic. - - virtual SVal EvalBinOp(GRExprEngine& Engine, const GRState *state, - BinaryOperator::Opcode Op, Loc L, NonLoc R) = 0; - // Calls. virtual void EvalCall(ExplodedNodeSet<GRState>& Dst, @@ -108,8 +74,7 @@ public: ReturnStmt* S, ExplodedNode<GRState>* Pred) {} - // Assumptions. - + // Assumptions. virtual const GRState* EvalAssume(const GRState *state, SVal Cond, bool Assumption) { return state; diff --git a/include/clang/Analysis/PathSensitive/SVals.h b/include/clang/Analysis/PathSensitive/SVals.h index e553940470..36137fb117 100644 --- a/include/clang/Analysis/PathSensitive/SVals.h +++ b/include/clang/Analysis/PathSensitive/SVals.h @@ -254,12 +254,12 @@ public: } // Transfer functions for binary/unary operations on ConcreteInts. - SVal EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op, + SVal evalBinOp(ValueManager &ValMgr, BinaryOperator::Opcode Op, const ConcreteInt& R) const; - ConcreteInt EvalComplement(BasicValueFactory& BasicVals) const; + ConcreteInt evalComplement(ValueManager &ValMgr) const; - ConcreteInt EvalMinus(BasicValueFactory& BasicVals, UnaryOperator* U) const; + ConcreteInt evalMinus(ValueManager &ValMgr) const; // Implement isa<T> support. static inline bool classof(const SVal* V) { diff --git a/include/clang/Analysis/PathSensitive/Store.h b/include/clang/Analysis/PathSensitive/Store.h index cbe0b3c835..5aa53507fd 100644 --- a/include/clang/Analysis/PathSensitive/Store.h +++ b/include/clang/Analysis/PathSensitive/Store.h @@ -138,7 +138,7 @@ public: /// EvalBinOp - Perform pointer arithmetic. virtual SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode Op, - Loc lhs, NonLoc rhs) { + Loc lhs, NonLoc rhs, QualType resultTy) { return UnknownVal(); } diff --git a/include/clang/Analysis/PathSensitive/ValueManager.h b/include/clang/Analysis/PathSensitive/ValueManager.h index d8e557f760..de318a0f03 100644 --- a/include/clang/Analysis/PathSensitive/ValueManager.h +++ b/include/clang/Analysis/PathSensitive/ValueManager.h @@ -87,14 +87,18 @@ public: return nonloc::ConcreteInt(BasicVals.getZeroWithPtrWidth(false)); } - NonLoc makeIntVal(const IntegerLiteral* I) { + nonloc::ConcreteInt makeIntVal(const IntegerLiteral* I) { return nonloc::ConcreteInt(BasicVals.getValue(I->getValue(), I->getType()->isUnsignedIntegerType())); } - NonLoc makeIntVal(const llvm::APSInt& V) { + nonloc::ConcreteInt makeIntVal(const llvm::APSInt& V) { return nonloc::ConcreteInt(BasicVals.getValue(V)); } + + loc::ConcreteInt makeIntLocVal(const llvm::APSInt &v) { + return loc::ConcreteInt(BasicVals.getValue(v)); + } NonLoc makeIntVal(const llvm::APInt& V, bool isUnsigned) { return nonloc::ConcreteInt(BasicVals.getValue(V, isUnsigned)); diff --git a/include/clang/Frontend/Analyses.def b/include/clang/Frontend/Analyses.def index 3492d09c10..ad799c3a8b 100644 --- a/include/clang/Frontend/Analyses.def +++ b/include/clang/Frontend/Analyses.def @@ -41,13 +41,9 @@ ANALYSIS(WarnObjCDealloc, "warn-objc-missing-dealloc", ANALYSIS(WarnObjCUnusedIvars, "warn-objc-unused-ivars", "Warn about private ivars that are never used", ObjCImplementation) -ANALYSIS(CheckerSimple, "checker-simple", - "Perform simple path-sensitive checks.", Code) - ANALYSIS(CheckerCFRef, "checker-cfref", "Run the [Core] Foundation reference count checker", Code) - #ifndef ANALYSIS_STORE #define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) #endif diff --git a/lib/Analysis/BugReporter.cpp b/lib/Analysis/BugReporter.cpp index 9c9029cfff..38ea458a65 100644 --- a/lib/Analysis/BugReporter.cpp +++ b/lib/Analysis/BugReporter.cpp @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// // // This file defines BugReporter, a utility class for generating -// PathDiagnostics for analyses based on GRSimpleVals. +// PathDiagnostics. // //===----------------------------------------------------------------------===// diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp index 5e542a3c48..f4a28e0c19 100644 --- a/lib/Analysis/CFRefCount.cpp +++ b/lib/Analysis/CFRefCount.cpp @@ -12,7 +12,6 @@ // //===----------------------------------------------------------------------===// -#include "GRSimpleVals.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/SourceManager.h" #include "clang/Analysis/PathSensitive/GRExprEngineBuilders.h" @@ -22,6 +21,7 @@ #include "clang/Analysis/PathDiagnostic.h" #include "clang/Analysis/PathSensitive/BugReporter.h" #include "clang/Analysis/PathSensitive/SymbolManager.h" +#include "clang/Analysis/PathSensitive/GRTransferFuncs.h" #include "clang/AST/DeclObjC.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" @@ -1826,7 +1826,7 @@ static const GRState * SendAutorelease(const GRState *state, namespace { -class VISIBILITY_HIDDEN CFRefCount : public GRSimpleVals { +class VISIBILITY_HIDDEN CFRefCount : public GRTransferFuncs { public: class BindingsPrinter : public GRState::Printer { public: @@ -2789,10 +2789,7 @@ void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst, if (Summ.getArg(idx) == DoNothingByRef) continue; - // Invalidate the value of the variable passed by reference. - - // FIXME: Either this logic should also be replicated in GRSimpleVals - // or should be pulled into a separate "constraint engine." + // Invalidate the value of the variable passed by reference. // FIXME: We can have collisions on the conjured symbol if the // expression *I also creates conjured symbols. We probably want @@ -2941,11 +2938,10 @@ void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst, default: assert (false && "Unhandled RetEffect."); break; - case RetEffect::NoRet: { - + case RetEffect::NoRet: { // Make up a symbol for the return value (not reference counted). - // FIXME: This is basically copy-and-paste from GRSimpleVals. We - // should compose behavior, not copy it. + // FIXME: Most of this logic is not specific to the retain/release + // checker. // FIXME: We eventually should handle structs and other compound types // that are returned by value. diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt index e064e3c71a..7d6a619736 100644 --- a/lib/Analysis/CMakeLists.txt +++ b/lib/Analysis/CMakeLists.txt @@ -18,15 +18,14 @@ add_clang_library(clangAnalysis GRCoreEngine.cpp GRExprEngine.cpp GRExprEngineInternalChecks.cpp - GRSimpleVals.cpp GRState.cpp - GRTransferFuncs.cpp LiveVariables.cpp MemRegion.cpp PathDiagnostic.cpp RangeConstraintManager.cpp RegionStore.cpp SimpleConstraintManager.cpp + SimpleSValuator.cpp Store.cpp SVals.cpp SymbolManager.cpp diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index d3df92df34..779d70661c 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -15,7 +15,6 @@ #include "clang/Analysis/PathSensitive/GRExprEngine.h" #include "clang/Analysis/PathSensitive/GRExprEngineBuilders.h" -#include "clang/Analysis/PathSensitive/BugReporter.h" #include "clang/AST/ParentMap.h" #include "clang/AST/StmtObjC.h" #include "clang/Basic/Builtins.h" @@ -126,6 +125,7 @@ GRExprEngine::GRExprEngine(CFG& cfg, Decl& CD, ASTContext& Ctx, StateMgr(G.getContext(), SMC, CMC, G.getAllocator(), cfg, CD, L), SymMgr(StateMgr.getSymbolManager()), ValMgr(StateMgr.getValueManager()), + SVator(clang::CreateSimpleSValuator(ValMgr)), // FIXME: Generalize later. CurrentStmt(NULL), NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL), RaiseSel(GetNullarySelector("raise", G.getContext())), @@ -1296,9 +1296,8 @@ static bool EvalOSAtomicCompareAndSwap(ExplodedNodeSet<GRState>& Dst, SVal oldValueVal = stateLoad->getSVal(oldValueExpr); // Perform the comparison. - SVal Cmp = Engine.EvalBinOp(stateLoad, - BinaryOperator::EQ, theValueVal, oldValueVal, - Engine.getContext().IntTy); + SVal Cmp = Engine.EvalBinOp(stateLoad, BinaryOperator::EQ, theValueVal, + oldValueVal, Engine.getContext().IntTy); const GRState *stateEqual = stateLoad->assume(Cmp, true); @@ -2562,7 +2561,7 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, NodeTy* Pred, case UnaryOperator::Minus: // FIXME: Do we need to handle promotions? - state = state->bindExpr(U, EvalMinus(U, cast<NonLoc>(V))); + state = state->bindExpr(U, EvalMinus(cast<NonLoc>(V))); break; case UnaryOperator::LNot: @@ -2571,25 +2570,21 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, NodeTy* Pred, // // Note: technically we do "E == 0", but this is the same in the // transfer functions as "0 == E". + SVal Result; if (isa<Loc>(V)) { Loc X = ValMgr.makeNull(); - SVal Result = EvalBinOp(state,BinaryOperator::EQ, cast<Loc>(V), X, - U->getType()); - state = state->bindExpr(U, Result); + Result = EvalBinOp(state, BinaryOperator::EQ, cast<Loc>(V), X, + U->getType()); } else { nonloc::ConcreteInt X(getBasicVals().getValue(0, Ex->getType())); -#if 0 - SVal Result = EvalBinOp(BinaryOperator::EQ, cast<NonLoc>(V), X); - state = SetSVal(state, U, Result); -#else - EvalBinOp(Dst, U, BinaryOperator::EQ, cast<NonLoc>(V), X, *I, - U->getType()); - continue; -#endif + Result = EvalBinOp(BinaryOperator::EQ, cast<NonLoc>(V), X, + U->getType()); } + state = state->bindExpr(U, Result); + break; } @@ -2640,8 +2635,8 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, NodeTy* Pred, Builder->getCurrentBlockCount()); // If the value is a location, ++/-- should always preserve - // non-nullness. Check if the original value was non-null, and if so propagate - // that constraint. + // non-nullness. Check if the original value was non-null, and if so + // propagate that constraint. if (Loc::IsLocType(U->getType())) { SVal Constraint = EvalBinOp(state, BinaryOperator::EQ, V2, ValMgr.makeZeroVal(U->getType()), @@ -2907,9 +2902,8 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, if (B->isAssignmentOp()) break; - // Process non-assignements except commas or short-circuited - // logical expressions (LAnd and LOr). - + // Process non-assignments except commas or short-circuited + // logical expressions (LAnd and LOr). SVal Result = EvalBinOp(state, Op, LeftV, RightV, B->getType()); if (Result.isUnknown()) { @@ -3024,7 +3018,7 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, } // Compute the result of the operation. - SVal Result = EvalCast(EvalBinOp(state, Op, V, RightV, CTy), + SVal Result = EvalCast(EvalBinOp(state, Op, V, RightV, CTy), B->getType()); if (Result.isUndef()) { @@ -3073,26 +3067,6 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, // Transfer-function Helpers. //===----------------------------------------------------------------------===// -void GRExprEngine::EvalBinOp(ExplodedNodeSet<GRState>& Dst, Expr* Ex, - BinaryOperator::Opcode Op, - NonLoc L, NonLoc R, - ExplodedNode<GRState>* Pred, QualType T) { - - GRStateSet OStates; - EvalBinOp(OStates, GetState(Pred), Ex, Op, L, R, T); - - for (GRStateSet::iterator I=OStates.begin(), E=OStates.end(); I!=E; ++I) - MakeNode(Dst, Ex, Pred, *I); -} - -void GRExprEngine::EvalBinOp(GRStateSet& OStates, const GRState* state, - Expr* Ex, BinaryOperator::Opcode Op, - NonLoc L, NonLoc R, QualType T) { - - GRStateSet::AutoPopulate AP(OStates, state); - if (R.isValid()) getTF().EvalBinOpNN(OStates, *this, state, Ex, Op, L, R, T); -} - SVal GRExprEngine::EvalBinOp(const GRState* state, BinaryOperator::Opcode Op, SVal L, SVal R, QualType T) { @@ -3104,9 +3078,9 @@ SVal GRExprEngine::EvalBinOp(const GRState* state, BinaryOperator::Opcode Op, if (isa<Loc>(L)) { if (isa<Loc>(R)) - return getTF().EvalBinOp(*this, Op, cast<Loc>(L), cast<Loc>(R)); + return SVator->EvalBinOpLL(Op, cast<Loc>(L), cast<Loc>(R), T); else - return getTF().EvalBinOp(*this, state, Op, cast<Loc>(L), cast<NonLoc>(R)); + return SVator->EvalBinOpLN(state, Op, cast<Loc>(L), cast<NonLoc>(R), T); } if (isa<Loc>(R)) { @@ -3116,11 +3090,10 @@ SVal GRExprEngine::EvalBinOp(const GRState* state, BinaryOperator::Opcode Op, assert (Op == BinaryOperator::Add || Op == BinaryOperator::Sub); // Commute the operands. - return getTF().EvalBinOp(*this, state, Op, cast<Loc>(R), cast<NonLoc>(L)); + return SVator->EvalBinOpLN(state, Op, cast<Loc>(R), cast<NonLoc>(L), T); } else - return getTF().DetermEvalBinOpNN(*this, Op, cast<NonLoc>(L), - cast<NonLoc>(R), T); + return SVator->EvalBinOpNN(Op, cast<NonLoc>(L), cast<NonLoc>(R), T); } //===----------------------------------------------------------------------===// diff --git a/lib/Analysis/GRSimpleVals.cpp b/lib/Analysis/GRSimpleVals.cpp deleted file mode 100644 index 9a1b2fc05e..0000000000 --- a/lib/Analysis/GRSimpleVals.cpp +++ /dev/null @@ -1,414 +0,0 @@ -// GRSimpleVals.cpp - Transfer functions for tracking simple values -*- C++ -*-- -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines GRSimpleVals, a sub-class of GRTransferFuncs that -// provides transfer functions for performing simple value tracking with -// limited support for symbolics. -// -//===----------------------------------------------------------------------===// - -#include "GRSimpleVals.h" -#include "BasicObjCFoundationChecks.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Analysis/PathDiagnostic.h" -#include "clang/Analysis/PathSensitive/GRState.h" -#include "clang/Analysis/PathSensitive/BugReporter.h" -#include "clang/Analysis/LocalCheckers.h" -#include "clang/Analysis/PathSensitive/GRExprEngine.h" -#include "llvm/Support/Compiler.h" -#include <sstream> - -using namespace clang; - -//===----------------------------------------------------------------------===// -// Transfer Function creation for External clients. -//===----------------------------------------------------------------------===// - -GRTransferFuncs* clang::MakeGRSimpleValsTF() { return new GRSimpleVals(); } - -//===----------------------------------------------------------------------===// -// Transfer function for Casts. -//===----------------------------------------------------------------------===// - -SVal GRSimpleVals::EvalCast(GRExprEngine& Eng, NonLoc X, QualType T) { - - if (!isa<nonloc::ConcreteInt>(X)) - return UnknownVal(); - - bool isLocType = Loc::IsLocType(T); - - // Only handle casts from integers to integers. - if (!isLocType && !T->isIntegerType()) - return UnknownVal(); - - BasicValueFactory& BasicVals = Eng.getBasicVals(); - - llvm::APSInt V = cast<nonloc::ConcreteInt>(X).getValue(); - V.setIsUnsigned(T->isUnsignedIntegerType() || Loc::IsLocType(T)); - V.extOrTrunc(Eng.getContext().getTypeSize(T)); - - if (isLocType) - return loc::ConcreteInt(BasicVals.getValue(V)); - else - return nonloc::ConcreteInt(BasicVals.getValue(V)); -} - -// Casts. - -SVal GRSimpleVals::EvalCast(GRExprEngine& Eng, Loc X, QualType T) { - - // Casts from pointers -> pointers, just return the lval. - // - // Casts from pointers -> references, just return the lval. These - // can be introduced by the frontend for corner cases, e.g - // casting from va_list* to __builtin_va_list&. - // - assert (!X.isUnknownOrUndef()); - - if (Loc::IsLocType(T) || T->isReferenceType()) - return X; - - // FIXME: Handle transparent unions where a value can be "transparently" - // lifted into a union type. - if (T->isUnionType()) - return UnknownVal(); - - assert (T->isIntegerType()); - BasicValueFactory& BasicVals = Eng.getBasicVals(); - unsigned BitWidth = Eng.getContext().getTypeSize(T); - - if (!isa<loc::ConcreteInt>(X)) - return Eng.getValueManager().makeLocAsInteger(X, BitWidth); - - llvm::APSInt V = cast<loc::ConcreteInt>(X).getValue(); - V.setIsUnsigned(T->isUnsignedIntegerType() || Loc::IsLocType(T)); - V.extOrTrunc(BitWidth); - return nonloc::ConcreteInt(BasicVals.getValue(V)); -} - -// Unary operators. - -SVal GRSimpleVals::EvalMinus(GRExprEngine& Eng, UnaryOperator* U, NonLoc X){ - - switch (X.getSubKind()) { - - case nonloc::ConcreteIntKind: - return cast<nonloc::ConcreteInt>(X).EvalMinus(Eng.getBasicVals(), U); - - default: - return UnknownVal(); - } -} - -SVal GRSimpleVals::EvalComplement(GRExprEngine& Eng, NonLoc X) { - - switch (X.getSubKind()) { - - case nonloc::ConcreteIntKind: - return cast<nonloc::ConcreteInt>(X).EvalComplement(Eng.getBasicVals()); - - default: - return UnknownVal(); - } -} - -// Binary operators. - -static unsigned char LNotOpMap[] = { - (unsigned char) BinaryOperator::GE, /* LT => GE */ - (unsigned char) BinaryOperator::LE, /* GT => LE */ - (unsigned char) BinaryOperator::GT, /* LE => GT */ - (unsigned char) BinaryOperator::LT, /* GE => LT */ - (unsigned char) BinaryOperator::NE, /* EQ => NE */ - (unsigned char) BinaryOperator::EQ /* NE => EQ */ -}; - -SVal GRSimpleVals::DetermEvalBinOpNN(GRExprEngine& Eng, - BinaryOperator::Opcode Op, - NonLoc L, NonLoc R, - QualType T) { - BasicValueFactory& BasicVals = Eng.getBasicVals(); - ValueManager& ValMgr = Eng.getValueManager(); - unsigned subkind = L.getSubKind(); - - while (1) { - - switch (subkind) { - default: - return UnknownVal(); - - case nonloc::LocAsIntegerKind: { - Loc LL = cast<nonloc::LocAsInteger>(L).getLoc(); - - switch (R.getSubKind()) { - case nonloc::LocAsIntegerKind: - return EvalBinOp(Eng, Op, LL, - cast<nonloc::LocAsInteger>(R).getLoc()); - - case nonloc::ConcreteIntKind: { - // Transform the integer into a location and compare. - ASTContext& Ctx = Eng.getContext(); - llvm::APSInt V = cast<nonloc::ConcreteInt>(R).getValue(); - V.setIsUnsigned(true); - V.extOrTrunc(Ctx.getTypeSize(Ctx.VoidPtrTy)); - return EvalBinOp(Eng, Op, LL, ValMgr.makeLoc(V)); - } - - default: - switch (Op) { - case BinaryOperator::EQ: - return ValMgr.makeTruthVal(false); - case BinaryOperator::NE: - return ValMgr.makeTruthVal(true); - default: - // This case also handles pointer arithmetic. - return UnknownVal(); - } - } - } - - case nonloc::SymExprValKind: { - // Logical not? - if (!(Op == BinaryOperator::EQ && R.isZeroConstant())) - return UnknownVal(); - - const SymExpr &SE=*cast<nonloc::SymExprVal>(L).getSymbolicExpression(); - - // Only handle ($sym op constant) for now. - if (const SymIntExpr *E = dyn_cast<SymIntExpr>(&SE)) { - BinaryOperator::Opcode Opc = E->getOp |