diff options
Diffstat (limited to 'lib/Analysis')
-rw-r--r-- | lib/Analysis/AnalysisContext.cpp | 4 | ||||
-rw-r--r-- | lib/Analysis/BasicConstraintManager.cpp | 11 | ||||
-rw-r--r-- | lib/Analysis/BugReporter.cpp | 19 | ||||
-rw-r--r-- | lib/Analysis/CFRefCount.cpp | 25 | ||||
-rw-r--r-- | lib/Analysis/CheckSecuritySyntaxOnly.cpp | 18 | ||||
-rw-r--r-- | lib/Analysis/Environment.cpp | 7 | ||||
-rw-r--r-- | lib/Analysis/GRExprEngine.cpp | 133 | ||||
-rw-r--r-- | lib/Analysis/GRState.cpp | 3 | ||||
-rw-r--r-- | lib/Analysis/MemRegion.cpp | 65 | ||||
-rw-r--r-- | lib/Analysis/OSAtomicChecker.cpp | 28 | ||||
-rw-r--r-- | lib/Analysis/RangeConstraintManager.cpp | 8 | ||||
-rw-r--r-- | lib/Analysis/RegionStore.cpp | 223 | ||||
-rw-r--r-- | lib/Analysis/ReturnStackAddressChecker.cpp | 14 | ||||
-rw-r--r-- | lib/Analysis/SVals.cpp | 4 | ||||
-rw-r--r-- | lib/Analysis/SValuator.cpp | 8 | ||||
-rw-r--r-- | lib/Analysis/SimpleConstraintManager.cpp | 47 | ||||
-rw-r--r-- | lib/Analysis/SimpleConstraintManager.h | 3 | ||||
-rw-r--r-- | lib/Analysis/SimpleSValuator.cpp | 8 | ||||
-rw-r--r-- | lib/Analysis/Store.cpp | 43 |
19 files changed, 454 insertions, 217 deletions
diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp index 97e6d91..2093b5e 100644 --- a/lib/Analysis/AnalysisContext.cpp +++ b/lib/Analysis/AnalysisContext.cpp @@ -18,6 +18,7 @@ #include "clang/Analysis/CFG.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/ParentMap.h" #include "clang/AST/StmtVisitor.h" #include "clang/Analysis/Support/BumpVector.h" @@ -38,6 +39,9 @@ Stmt *AnalysisContext::getBody() { return MD->getBody(); else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) return BD->getBody(); + else if (const FunctionTemplateDecl *FunTmpl + = dyn_cast_or_null<FunctionTemplateDecl>(D)) + return FunTmpl->getTemplatedDecl()->getBody(); llvm_unreachable("unknown code decl"); } diff --git a/lib/Analysis/BasicConstraintManager.cpp b/lib/Analysis/BasicConstraintManager.cpp index 6c3f7b2..6dfc470 100644 --- a/lib/Analysis/BasicConstraintManager.cpp +++ b/lib/Analysis/BasicConstraintManager.cpp @@ -49,8 +49,9 @@ class BasicConstraintManager : public SimpleConstraintManager { GRState::IntSetTy::Factory ISetFactory; public: - BasicConstraintManager(GRStateManager& statemgr) - : ISetFactory(statemgr.getAllocator()) {} + BasicConstraintManager(GRStateManager &statemgr, GRSubEngine &subengine) + : SimpleConstraintManager(subengine), + ISetFactory(statemgr.getAllocator()) {} const GRState* AssumeSymNE(const GRState* state, SymbolRef sym, const llvm::APSInt& V); @@ -88,9 +89,9 @@ public: } // end anonymous namespace -ConstraintManager* clang::CreateBasicConstraintManager(GRStateManager& StateMgr) -{ - return new BasicConstraintManager(StateMgr); +ConstraintManager* clang::CreateBasicConstraintManager(GRStateManager& statemgr, + GRSubEngine &subengine) { + return new BasicConstraintManager(statemgr, subengine); } const GRState* diff --git a/lib/Analysis/BugReporter.cpp b/lib/Analysis/BugReporter.cpp index e648269..2a9531d 100644 --- a/lib/Analysis/BugReporter.cpp +++ b/lib/Analysis/BugReporter.cpp @@ -1818,8 +1818,23 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) { R->getRanges(Beg, End); Diagnostic& Diag = getDiagnostic(); FullSourceLoc L(R->getLocation(), getSourceManager()); - unsigned ErrorDiag = Diag.getCustomDiagID(Diagnostic::Warning, - R->getShortDescription().c_str()); + + // Search the description for '%', as that will be interpretted as a + // format character by FormatDiagnostics. + llvm::StringRef desc = R->getShortDescription(); + unsigned ErrorDiag; + { + llvm::SmallString<512> TmpStr; + llvm::raw_svector_ostream Out(TmpStr); + for (llvm::StringRef::iterator I=desc.begin(), E=desc.end(); I!=E; ++I) + if (*I == '%') + Out << "%%"; + else + Out << *I; + + Out.flush(); + ErrorDiag = Diag.getCustomDiagID(Diagnostic::Warning, TmpStr); + } switch (End-Beg) { default: assert(0 && "Don't handle this many ranges yet!"); diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp index a15a8f1..5a15fbf 100644 --- a/lib/Analysis/CFRefCount.cpp +++ b/lib/Analysis/CFRefCount.cpp @@ -52,8 +52,8 @@ using namespace clang; // not release it." // -using llvm::CStrInCStrNoCase; -using llvm::StringsEqualNoCase; +using llvm::StrInStrNoCase; +using llvm::StringRef; enum NamingConvention { NoConvention, CreateRule, InitRule }; @@ -122,20 +122,20 @@ static NamingConvention deriveNamingConvention(Selector S) { break; case 3: // Methods starting with 'new' follow the create rule. - if (AtBeginning && StringsEqualNoCase("new", s, len)) + if (AtBeginning && StringRef(s, len).equals_lower("new")) C = CreateRule; break; case 4: // Methods starting with 'alloc' or contain 'copy' follow the // create rule - if (C == NoConvention && StringsEqualNoCase("copy", s, len)) + if (C == NoConvention && StringRef(s, len).equals_lower("copy")) C = CreateRule; else // Methods starting with 'init' follow the init rule. - if (AtBeginning && StringsEqualNoCase("init", s, len)) + if (AtBeginning && StringRef(s, len).equals_lower("init")) C = InitRule; break; case 5: - if (AtBeginning && StringsEqualNoCase("alloc", s, len)) + if (AtBeginning && StringRef(s, len).equals_lower("alloc")) C = CreateRule; break; } @@ -1372,11 +1372,11 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { // "AppendValue", or "SetAttribute", then we assume that arguments may // "escape." This means that something else holds on to the object, // allowing it be used even after its local retain count drops to 0. - ArgEffect E = (CStrInCStrNoCase(FName, "InsertValue") || - CStrInCStrNoCase(FName, "AddValue") || - CStrInCStrNoCase(FName, "SetValue") || - CStrInCStrNoCase(FName, "AppendValue") || - CStrInCStrNoCase(FName, "SetAttribute")) + ArgEffect E = (StrInStrNoCase(FName, "InsertValue") != StringRef::npos|| + StrInStrNoCase(FName, "AddValue") != StringRef::npos || + StrInStrNoCase(FName, "SetValue") != StringRef::npos || + StrInStrNoCase(FName, "AppendValue") != StringRef::npos|| + StrInStrNoCase(FName, "SetAttribute") != StringRef::npos) ? MayEscape : DoNothing; S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, E); @@ -1555,7 +1555,8 @@ RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD, if (S.isKeywordSelector()) { const std::string &str = S.getAsString(); assert(!str.empty()); - if (CStrInCStrNoCase(&str[0], "delegate:")) ReceiverEff = StopTracking; + if (StrInStrNoCase(str, "delegate:") != StringRef::npos) + ReceiverEff = StopTracking; } // Look for methods that return an owned object. diff --git a/lib/Analysis/CheckSecuritySyntaxOnly.cpp b/lib/Analysis/CheckSecuritySyntaxOnly.cpp index 3214101..f4874a5 100644 --- a/lib/Analysis/CheckSecuritySyntaxOnly.cpp +++ b/lib/Analysis/CheckSecuritySyntaxOnly.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/Basic/TargetInfo.h" #include "clang/Analysis/PathSensitive/BugReporter.h" #include "clang/Analysis/LocalCheckers.h" #include "clang/AST/StmtVisitor.h" @@ -18,6 +19,12 @@ using namespace clang; +static bool isArc4RandomAvailable(const ASTContext &Ctx) { + const llvm::Triple &T = Ctx.Target.getTriple(); + return T.getVendor() == llvm::Triple::Apple || + T.getOS() == llvm::Triple::FreeBSD; +} + namespace { class WalkAST : public StmtVisitor<WalkAST> { BugReporter &BR; @@ -29,11 +36,14 @@ class WalkAST : public StmtVisitor<WalkAST> { IdentifierInfo *II_random; enum { num_setids = 6 }; IdentifierInfo *II_setid[num_setids]; + + const bool CheckRand; public: WalkAST(BugReporter &br) : BR(br), II_gets(0), II_getpw(0), II_mktemp(0), - II_rand(), II_random(0), II_setid() {} + II_rand(), II_random(0), II_setid(), + CheckRand(isArc4RandomAvailable(BR.getContext())) {} // Statement visitor methods. void VisitCallExpr(CallExpr *CE); @@ -83,8 +93,10 @@ void WalkAST::VisitCallExpr(CallExpr *CE) { CheckCall_gets(CE, FD); CheckCall_getpw(CE, FD); CheckCall_mktemp(CE, FD); - CheckCall_rand(CE, FD); - CheckCall_random(CE, FD); + if (CheckRand) { + CheckCall_rand(CE, FD); + CheckCall_random(CE, FD); + } } // Recurse and check children. diff --git a/lib/Analysis/Environment.cpp b/lib/Analysis/Environment.cpp index dd2f08b..f04cf7b 100644 --- a/lib/Analysis/Environment.cpp +++ b/lib/Analysis/Environment.cpp @@ -37,7 +37,12 @@ SVal Environment::GetSVal(const Stmt *E, ValueManager& ValMgr) const { } case Stmt::IntegerLiteralClass: { - return ValMgr.makeIntVal(cast<IntegerLiteral>(E)); + // In C++, this expression may have been bound to a temporary object. + SVal const *X = ExprBindings.lookup(E); + if (X) + return *X; + else + return ValMgr.makeIntVal(cast<IntegerLiteral>(E)); } // Casts where the source and target type are the same diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index 2ce8edd..40c12c9 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -17,6 +17,7 @@ #include "clang/Analysis/PathSensitive/GRExprEngine.h" #include "clang/Analysis/PathSensitive/GRExprEngineBuilders.h" #include "clang/Analysis/PathSensitive/Checker.h" +#include "clang/AST/CharUnits.h" #include "clang/AST/ParentMap.h" #include "clang/AST/StmtObjC.h" #include "clang/Basic/Builtins.h" @@ -47,10 +48,9 @@ static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) { } -static bool CalleeReturnsReference(const CallExpr *CE) { +static QualType GetCalleeReturnType(const CallExpr *CE) { const Expr *Callee = CE->getCallee(); QualType T = Callee->getType(); - if (const PointerType *PT = T->getAs<PointerType>()) { const FunctionType *FT = PT->getPointeeType()->getAs<FunctionType>(); T = FT->getResultType(); @@ -58,16 +58,35 @@ static bool CalleeReturnsReference(const CallExpr *CE) { else { const BlockPointerType *BT = T->getAs<BlockPointerType>(); T = BT->getPointeeType()->getAs<FunctionType>()->getResultType(); - } - return T->isReferenceType(); + } + return T; +} + +static bool CalleeReturnsReference(const CallExpr *CE) { + return (bool) GetCalleeReturnType(CE)->getAs<ReferenceType>(); } static bool ReceiverReturnsReference(const ObjCMessageExpr *ME) { const ObjCMethodDecl *MD = ME->getMethodDecl(); if (!MD) return false; - return MD->getResultType()->isReferenceType(); + return MD->getResultType()->getAs<ReferenceType>(); +} + +#ifndef NDEBUG +static bool ReceiverReturnsReferenceOrRecord(const ObjCMessageExpr *ME) { + const ObjCMethodDecl *MD = ME->getMethodDecl(); + if (!MD) + return false; + QualType T = MD->getResultType(); + return T->getAs<RecordType>() || T->getAs<ReferenceType>(); +} + +static bool CalleeReturnsReferenceOrRecord(const CallExpr *CE) { + QualType T = GetCalleeReturnType(CE); + return T->getAs<ReferenceType>() || T->getAs<RecordType>(); } +#endif //===----------------------------------------------------------------------===// // Batch auditor. DEPRECATED. @@ -300,23 +319,27 @@ static void RegisterInternalChecks(GRExprEngine &Eng) { RegisterOSAtomicChecker(Eng); } -GRExprEngine::GRExprEngine(AnalysisManager &mgr) +GRExprEngine::GRExprEngine(AnalysisManager &mgr, GRTransferFuncs *tf) : AMgr(mgr), CoreEngine(mgr.getASTContext(), *this), G(CoreEngine.getGraph()), Builder(NULL), StateMgr(G.getContext(), mgr.getStoreManagerCreator(), - mgr.getConstraintManagerCreator(), G.getAllocator()), + mgr.getConstraintManagerCreator(), G.getAllocator(), + *this), SymMgr(StateMgr.getSymbolManager()), ValMgr(StateMgr.getValueManager()), SVator(ValMgr.getSValuator()), CurrentStmt(NULL), NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL), RaiseSel(GetNullarySelector("raise", G.getContext())), - BR(mgr, *this) -{ + BR(mgr, *this), TF(tf) { // Register internal checks. RegisterInternalChecks(*this); + + // FIXME: Eventually remove the TF object entirely. + TF->RegisterChecks(*this); + TF->RegisterPrinters(getStateManager().Printers); } GRExprEngine::~GRExprEngine() { @@ -330,13 +353,6 @@ GRExprEngine::~GRExprEngine() { // Utility methods. //===----------------------------------------------------------------------===// -void GRExprEngine::setTransferFunctionsAndCheckers(GRTransferFuncs* tf) { - StateMgr.TF = tf; - StateMgr.Checkers = &Checkers; - tf->RegisterChecks(*this); - tf->RegisterPrinters(getStateManager().Printers); -} - void GRExprEngine::AddCheck(GRSimpleAPICheck* A, Stmt::StmtClass C) { if (!BatchAuditor) BatchAuditor.reset(new MappedBatchAuditor(getGraph().getAllocator())); @@ -415,6 +431,25 @@ const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) { // Top-level transfer function logic (Dispatcher). //===----------------------------------------------------------------------===// +/// EvalAssume - Called by ConstraintManager. Used to call checker-specific +/// logic for handling assumptions on symbolic values. +const GRState *GRExprEngine::ProcessAssume(const GRState *state, SVal cond, + bool assumption) { + for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end(); + I != E; ++I) { + + if (!state) + return NULL; + + state = I->second->EvalAssume(state, cond, assumption); + } + + if (!state) + return NULL; + + return TF->EvalAssume(state, cond, assumption); +} + void GRExprEngine::ProcessStmt(CFGElement CE, GRStmtNodeBuilder& builder) { CurrentStmt = CE.getStmt(); PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), @@ -809,7 +844,7 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, case Stmt::CallExprClass: case Stmt::CXXOperatorCallExprClass: { CallExpr *C = cast<CallExpr>(Ex); - assert(CalleeReturnsReference(C)); + assert(CalleeReturnsReferenceOrRecord(C)); VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst, true); break; } @@ -840,7 +875,7 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, case Stmt::ObjCMessageExprClass: { ObjCMessageExpr *ME = cast<ObjCMessageExpr>(Ex); - assert(ReceiverReturnsReference(ME)); + assert(ReceiverReturnsReferenceOrRecord(ME)); VisitObjCMessageExpr(ME, Pred, Dst, true); return; } @@ -871,6 +906,11 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, case Stmt::UnaryOperatorClass: VisitUnaryOperator(cast<UnaryOperator>(Ex), Pred, Dst, true); return; + + // In C++, binding an rvalue to a reference requires to create an object. + case Stmt::IntegerLiteralClass: + CreateCXXTemporaryObject(Ex, Pred, Dst); + return; default: // Arbitrary subexpressions can return aggregate temporaries that @@ -1205,7 +1245,8 @@ void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) { do { nonloc::ConcreteInt CaseVal(getBasicVals().getValue(V1.Val.getInt())); - DefinedOrUnknownSVal Res = SVator.EvalEQ(DefaultSt, CondV, CaseVal); + DefinedOrUnknownSVal Res = SVator.EvalEQ(DefaultSt ? DefaultSt : state, + CondV, CaseVal); // Now "assume" that the case matches. if (const GRState* stateNew = state->Assume(Res, true)) { @@ -1220,11 +1261,17 @@ void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) { // Now "assume" that the case doesn't match. Add this state // to the default state (if it is feasible). - if (const GRState *stateNew = DefaultSt->Assume(Res, false)) { - defaultIsFeasible = true; - DefaultSt = stateNew; + if (DefaultSt) { + if (const GRState *stateNew = DefaultSt->Assume(Res, false)) { + defaultIsFeasible = true; + DefaultSt = stateNew; + } + else { + defaultIsFeasible = false; + DefaultSt = NULL; + } } - + // Concretize the next value in the range. if (V1.Val.getInt() == V2.Val.getInt()) break; @@ -2375,12 +2422,12 @@ void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex, ExplodedNode* Pred, ExplodedNodeSet& Dst) { QualType T = Ex->getTypeOfArgument(); - uint64_t amt; + CharUnits amt; if (Ex->isSizeOf()) { if (T == getContext().VoidTy) { // sizeof(void) == 1 byte. - amt = 1; + amt = CharUnits::One(); } else if (!T.getTypePtr()->isConstantSizeType()) { // FIXME: Add support for VLAs. @@ -2394,14 +2441,15 @@ void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex, } else { // All other cases. - amt = getContext().getTypeSize(T) / 8; + amt = getContext().getTypeSizeInChars(T); } } else // Get alignment of the type. - amt = getContext().getTypeAlign(T) / 8; + amt = CharUnits::fromQuantity(getContext().getTypeAlign(T) / 8); MakeNode(Dst, Ex, Pred, - GetState(Pred)->BindExpr(Ex, ValMgr.makeIntVal(amt, Ex->getType()))); + GetState(Pred)->BindExpr(Ex, + ValMgr.makeIntVal(amt.getQuantity(), Ex->getType()))); } @@ -2695,8 +2743,13 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, void GRExprEngine::VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred, ExplodedNodeSet & Dst) { // Get the this object region from StoreManager. - Loc V = getStoreManager().getThisObject(TE->getType()->getPointeeType()); - MakeNode(Dst, TE, Pred, GetState(Pred)->BindExpr(TE, V)); + const MemRegion *R = + ValMgr.getRegionManager().getCXXThisRegion(TE->getType(), + Pred->getLocationContext()); + + const GRState *state = GetState(Pred); + SVal V = state->getSVal(loc::MemRegionVal(R)); + MakeNode(Dst, TE, Pred, state->BindExpr(TE, V)); } void GRExprEngine::VisitAsmStmt(AsmStmt* A, ExplodedNode* Pred, @@ -2964,6 +3017,26 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, CheckerVisit(B, Dst, Tmp3, false); } +void GRExprEngine::CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + ExplodedNodeSet Tmp; + Visit(Ex, Pred, Tmp); + for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) { + const GRState *state = GetState(*I); + + // Bind the temporary object to the value of the expression. Then bind + // the expression to the location of the object. + SVal V = state->getSVal(Ex); + + const MemRegion *R = + ValMgr.getRegionManager().getCXXObjectRegion(Ex, + Pred->getLocationContext()); + + state = state->bindLoc(loc::MemRegionVal(R), V); + MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, loc::MemRegionVal(R))); + } +} + //===----------------------------------------------------------------------===// // Checker registration/lookup. //===----------------------------------------------------------------------===// diff --git a/lib/Analysis/GRState.cpp b/lib/Analysis/GRState.cpp index 7415fa5..051d465 100644 --- a/lib/Analysis/GRState.cpp +++ b/lib/Analysis/GRState.cpp @@ -267,6 +267,9 @@ bool ScanReachableSymbols::scan(SVal val) { if (loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(&val)) return scan(X->getRegion()); + if (nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(&val)) + return scan(X->getLoc()); + if (SymbolRef Sym = val.getAsSymbol()) return visitor.VisitSymbol(Sym); diff --git a/lib/Analysis/MemRegion.cpp b/lib/Analysis/MemRegion.cpp index 74fe3bf..87d60d3 100644 --- a/lib/Analysis/MemRegion.cpp +++ b/lib/Analysis/MemRegion.cpp @@ -17,6 +17,7 @@ #include "clang/Analysis/PathSensitive/MemRegion.h" #include "clang/Analysis/PathSensitive/ValueManager.h" #include "clang/Analysis/PathSensitive/AnalysisContext.h" +#include "clang/AST/CharUnits.h" #include "clang/AST/StmtVisitor.h" using namespace clang; @@ -215,6 +216,18 @@ void CompoundLiteralRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, ID.AddPointer(superRegion); } +void CXXThisRegion::ProfileRegion(llvm::FoldingSetNodeID &ID, + const PointerType *PT, + const MemRegion *sRegion) { + ID.AddInteger((unsigned) CXXThisRegionKind); + ID.AddPointer(PT); + ID.AddPointer(sRegion); +} + +void CXXThisRegion::Profile(llvm::FoldingSetNodeID &ID) const { + CXXThisRegion::ProfileRegion(ID, ThisPointerTy, superRegion); +} + void DeclRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl* D, const MemRegion* superRegion, Kind k) { ID.AddInteger((unsigned) k); @@ -292,14 +305,14 @@ void BlockDataRegion::Profile(llvm::FoldingSetNodeID& ID) const { } void CXXObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID, - QualType T, + Expr const *Ex, const MemRegion *sReg) { - ID.AddPointer(T.getTypePtr()); + ID.AddPointer(Ex); ID.AddPointer(sReg); } void CXXObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const { - ProfileRegion(ID, T, getSuperRegion()); + ProfileRegion(ID, Ex, getSuperRegion()); } //===----------------------------------------------------------------------===// @@ -343,6 +356,10 @@ void CompoundLiteralRegion::dumpToStream(llvm::raw_ostream& os) const { os << "{ " << (void*) CL << " }"; } +void CXXThisRegion::dumpToStream(llvm::raw_ostream &os) const { + os << "this"; +} + void ElementRegion::dumpToStream(llvm::raw_ostream& os) const { os << "element{" << superRegion << ',' << Index << ',' << getElementType().getAsString() << '}'; @@ -551,7 +568,7 @@ const SymbolicRegion *MemRegionManager::getSymbolicRegion(SymbolRef sym) { return getSubRegion<SymbolicRegion>(sym, getUnknownRegion()); } -const FieldRegion * +const FieldRegion* MemRegionManager::getFieldRegion(const FieldDecl* d, const MemRegion* superRegion){ return getSubRegion<FieldRegion>(d, superRegion); @@ -563,9 +580,22 @@ MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl* d, return getSubRegion<ObjCIvarRegion>(d, superRegion); } -const CXXObjectRegion * -MemRegionManager::getCXXObjectRegion(QualType T) { - return getSubRegion<CXXObjectRegion>(T, getUnknownRegion()); +const CXXObjectRegion* +MemRegionManager::getCXXObjectRegion(Expr const *E, + LocationContext const *LC) { + const StackFrameContext *SFC = LC->getCurrentStackFrame(); + assert(SFC); + return getSubRegion<CXXObjectRegion>(E, getStackLocalsRegion(SFC)); +} + +const CXXThisRegion* +MemRegionManager::getCXXThisRegion(QualType thisPointerTy, + const LocationContext *LC) { + const StackFrameContext *STC = LC->getCurrentStackFrame(); + assert(STC); + const PointerType *PT = thisPointerTy->getAs<PointerType>(); + assert(PT); + return getSubRegion<CXXThisRegion>(PT, getStackArgumentsRegion(STC)); } const AllocaRegion* @@ -592,20 +622,11 @@ bool MemRegion::hasStackStorage() const { return isa<StackSpaceRegion>(getMemorySpace()); } -bool MemRegion::hasHeapStorage() const { - return isa<HeapSpaceRegion>(getMemorySpace()); -} - -bool MemRegion::hasHeapOrStackStorage() const { - const MemSpaceRegion *MS = getMemorySpace(); - return isa<StackSpaceRegion>(MS) || isa<HeapSpaceRegion>(MS); -} - -bool MemRegion::hasGlobalsStorage() const { - return isa<GlobalsSpaceRegion>(getMemorySpace()); +bool MemRegion::hasStackNonParametersStorage() const { + return isa<StackLocalsSpaceRegion>(getMemorySpace()); } -bool MemRegion::hasParametersStorage() const { +bool MemRegion::hasStackParametersStorage() const { return isa<StackArgumentsSpaceRegion>(getMemorySpace()); } @@ -669,7 +690,7 @@ static bool IsCompleteType(ASTContext &Ctx, QualType Ty) { } RegionRawOffset ElementRegion::getAsRawOffset() const { - int64_t offset = 0; + CharUnits offset = CharUnits::Zero(); const ElementRegion *ER = this; const MemRegion *superR = NULL; ASTContext &C = getContext(); @@ -694,7 +715,7 @@ RegionRawOffset ElementRegion::getAsRawOffset() const { break; } - int64_t size = (int64_t) (C.getTypeSize(elemType) / 8); + CharUnits size = C.getTypeSizeInChars(elemType); offset += (i * size); } @@ -707,7 +728,7 @@ RegionRawOffset ElementRegion::getAsRawOffset() const { } assert(superR && "super region cannot be NULL"); - return RegionRawOffset(superR, offset); + return RegionRawOffset(superR, offset.getQuantity()); } //===----------------------------------------------------------------------===// diff --git a/lib/Analysis/OSAtomicChecker.cpp b/lib/Analysis/OSAtomicChecker.cpp index cf16796..9d34e9e 100644 --- a/lib/Analysis/OSAtomicChecker.cpp +++ b/lib/Analysis/OSAtomicChecker.cpp @@ -103,19 +103,9 @@ bool OSAtomicChecker::EvalOSAtomicCompareAndSwap(CheckerContext &C, SVal location = state->getSVal(theValueExpr); // Here we should use the value type of the region as the load type. QualType LoadTy; - if (const MemRegion *R = location.getAsRegion()) { - // We must be careful, as SymbolicRegions aren't typed. - const MemRegion *strippedR = R->StripCasts(); - // FIXME: This isn't quite the right solution. One test case in 'test/Analysis/NSString.m' - // is giving the wrong result. - const TypedRegion *typedR = - isa<SymbolicRegion>(strippedR) ? cast<TypedRegion>(R) : - dyn_cast<TypedRegion>(strippedR); - - if (typedR) { - LoadTy = typedR->getValueType(Ctx); - location = loc::MemRegionVal(typedR); - } + if (const TypedRegion *TR = + dyn_cast_or_null<TypedRegion>(location.getAsRegion())) { + LoadTy = TR->getValueType(Ctx); } Engine.EvalLoad(Tmp, const_cast<Expr *>(theValueExpr), C.getPredecessor(), state, location, OSAtomicLoadTag, LoadTy); @@ -184,14 +174,22 @@ bool OSAtomicChecker::EvalOSAtomicCompareAndSwap(CheckerContext &C, E2 = TmpStore.end(); I2 != E2; ++I2) { ExplodedNode *predNew = *I2; const GRState *stateNew = predNew->getState(); - SVal Res = Engine.getValueManager().makeTruthVal(true, CE->getType()); + // Check for 'void' return type if we have a bogus function prototype. + SVal Res = UnknownVal(); + QualType T = CE->getType(); + if (!T->isVoidType()) + Res = Engine.getValueManager().makeTruthVal(true, T); C.GenerateNode(stateNew->BindExpr(CE, Res), predNew); } } // Were they not equal? if (const GRState *stateNotEqual = stateLoad->Assume(Cmp, false)) { - SVal Res = Engine.getValueManager().makeTruthVal(false, CE->getType()); + // Check for 'void' return type if we have a bogus function prototype. + SVal Res = UnknownVal(); + QualType T = CE->getType(); + if (!T->isVoidType()) + Res = Engine.getValueManager().makeTruthVal(false, CE->getType()); C.GenerateNode(stateNotEqual->BindExpr(CE, Res), N); } } diff --git a/lib/Analysis/RangeConstraintManager.cpp b/lib/Analysis/RangeConstraintManager.cpp index 7330b62..2cf3dfb 100644 --- a/lib/Analysis/RangeConstraintManager.cpp +++ b/lib/Analysis/RangeConstraintManager.cpp @@ -234,7 +234,8 @@ namespace { class RangeConstraintManager : public SimpleConstraintManager{ RangeSet GetRange(const GRState *state, SymbolRef sym); public: - RangeConstraintManager() {} + RangeConstraintManager(GRSubEngine &subengine) + : SimpleConstraintManager(subengine) {} const GRState* AssumeSymNE(const GRState* St, SymbolRef sym, const llvm::APSInt& V); @@ -273,8 +274,9 @@ private: } // end anonymous namespace -ConstraintManager* clang::CreateRangeConstraintManager(GRStateManager&) { - return new RangeConstraintManager(); +ConstraintManager* clang::CreateRangeConstraintManager(GRStateManager&, + GRSubEngine &subeng) { + return new RangeConstraintManager(subeng); } const llvm::APSInt* RangeConstraintManager::getSymVal(const GRState* St, diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp index 3bc9dcc..9b5b44b 100644 --- a/lib/Analysis/RegionStore.cpp +++ b/lib/Analysis/RegionStore.cpp @@ -28,9 +28,12 @@ using namespace clang; -#define HEAP_UNDEFINED 0 #define USE_EXPLICIT_COMPOUND 0 +//===----------------------------------------------------------------------===// +// Representation of value bindings. +//===----------------------------------------------------------------------===// + namespace { class BindingVal { public: @@ -77,8 +80,41 @@ llvm::raw_ostream& operator<<(llvm::raw_ostream& os, BindingVal V) { } } // end llvm namespace +//===----------------------------------------------------------------------===// +// Representation of binding keys. +//===----------------------------------------------------------------------===// + +namespace { + class BindingKey : public std::pair<const MemRegion*, uint64_t> { +public: + explicit BindingKey(const MemRegion *r, uint64_t offset) + : std::pair<const MemRegion*,uint64_t>(r, offset) { assert(r); } + + const MemRegion *getRegion() const { return first; } + uint64_t getOffset() const { return second; } + + void Profile(llvm::FoldingSetNodeID& ID) const { + ID.AddPointer(getRegion()); + ID.AddInteger(getOffset()); + } + + static BindingKey Make(const MemRegion *R); +}; +} // end anonymous namespace + +namespace llvm { + static inline + llvm::raw_ostream& operator<<(llvm::raw_ostream& os, BindingKey K) { + os << '(' << K.getRegion() << ',' << K.getOffset() << ')'; + return os; + } +} // end llvm namespace + +//===----------------------------------------------------------------------===// // Actual Store type. -typedef llvm::ImmutableMap<const MemRegion*, BindingVal> RegionBindings; +//===----------------------------------------------------------------------===// + +typedef llvm::ImmutableMap<BindingKey, BindingVal> RegionBindings; //===----------------------------------------------------------------------===// // Fine-grained control of RegionStoreManager. @@ -283,6 +319,16 @@ private: void RemoveSubRegionBindings(RegionBindings &B, const MemRegion *R, RegionStoreSubRegionMap &M); + RegionBindings Add(RegionBindings B, BindingKey K, BindingVal V); + RegionBindings Add(RegionBindings B, const MemRegion *R, BindingVal V); + + const BindingVal *Lookup(RegionBindings B, BindingKey K); + const BindingVal *Lookup(RegionBindings B, const MemRegion *R); + + RegionBindings Remove(RegionBindings B, BindingKey K); + RegionBindings Remove(RegionBindings B, const MemRegion *R); + Store Remove(Store store, BindingKey K); + public: const GRState *Bind(const GRState *state, Loc LV, SVal V); @@ -308,6 +354,7 @@ public: Store KillStruct(Store store, const TypedRegion* R); Store Remove(Store store, Loc LV); + //===------------------------------------------------------------------===// // Loading values from regions. @@ -438,7 +485,7 @@ RegionStoreManager::getRegionStoreSubRegionMap(Store store) { llvm::SmallVector<const SubRegion*, 10> WL; for (RegionBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) - if (const SubRegion *R = dyn_cast<SubRegion>(I.getKey())) + if (const SubRegion *R = dyn_cast<SubRegion>(I.getKey().getRegion())) M->process(WL, R); // We also need to record in the subregion map "intermediate" regions that @@ -467,8 +514,8 @@ void RegionStoreManager::RemoveSubRegionBindings(RegionBindings &B, for (llvm::tie(I, E) = M.begin_end(R); I != E; ++I) RemoveSubRegionBindings(B, *I, M); - - B = RBFactory.Remove(B, R); + + B = Remove(B, R); } const GRState *RegionStoreManager::InvalidateRegions(const GRState *state, @@ -544,8 +591,8 @@ const GRState *RegionStoreManager::InvalidateRegions(const GRState *state, // Invalidate the region by setting its default value to // conjured symbol. The type of the symbol is irrelavant. DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, Ctx.IntTy, - Count); - B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default)); + Count); + B = Add(B, R, BindingVal(V, BindingVal::Default)); continue; } @@ -566,7 +613,7 @@ const GRState *RegionStoreManager::InvalidateRegions(const GRState *state, // conjured symbol. The type of the symbol is irrelavant. DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, Ctx.IntTy, Count); - B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default)); + B = Add(B, R, BindingVal(V, BindingVal::Default)); continue; } @@ -574,7 +621,7 @@ const GRState *RegionStoreManager::InvalidateRegions(const GRState *state, // Set the default value of the array to conjured symbol. DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, AT->getElementType(), Count); - B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default)); + B = Add(B, R, BindingVal(V, BindingVal::Default)); continue; } @@ -583,14 +630,14 @@ const GRState *RegionStoreManager::InvalidateRegions(const GRState *state, // For fields and elements whose super region has also been invalidated, // only remove the old binding. The super region will get set with a // default value from which we can lazily derive a new symbolic value. - B = RBFactory.Remove(B, R); + B = Remove(B, R); continue; } // Invalidate the binding. DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, T, Count); assert(SymbolManager::canSymbolicate(T) || V.isUnknown()); - B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Direct)); + B = Add(B, R, BindingVal(V, BindingVal::Direct)); } // Create a new state with the updated bindings. @@ -723,6 +770,8 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state, const MemRegion *R) { switch (R->getKind()) { + case MemRegion::CXXThisRegionKind: + assert(0 && "Cannot get size of 'this' region"); case MemRegion::GenericMemSpaceRegionKind: case MemRegion::StackLocalsSpaceRegionKind: case MemRegion::StackArgumentsSpaceRegionKind: @@ -877,6 +926,9 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state, // Technically this can happen if people do funny things with casts. return UnknownVal(); + case MemRegion::CXXThisRegionKind: + assert(0 && + "Cannot perform pointer arithmetic on implicit argument 'this'"); case MemRegion::GenericMemSpaceRegionKind: case MemRegion::StackLocalsSpaceRegionKind: case MemRegion::StackArgumentsSpaceRegionKind: @@ -921,7 +973,7 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state, Optional<SVal> RegionStoreManager::getDirectBinding(RegionBindings B, const MemRegion *R) { - if (const BindingVal *BV = B.lookup(R)) + if (const BindingVal *BV = Lookup(B, R)) return Optional<SVal>::create(BV->getDirectValue()); return Optional<SVal>(); @@ -935,7 +987,7 @@ Optional<SVal> RegionStoreManager::getDefaultBinding(RegionBindings B, if (TR->getValueType(getContext())->isUnionType()) return UnknownVal(); - if (BindingVal const *V = B.lookup(R)) + if (const BindingVal *V = Lookup(B, R)) return Optional<SVal>::create(V->getDefaultValue()); return Optional<SVal>(); @@ -943,7 +995,7 @@ Optional<SVal> RegionStoreManager::getDefaultBinding(RegionBindings B, Optional<SVal> RegionStoreManager::getBinding(RegionBindings B, const MemRegion *R) { - if (const BindingVal *BV = B.lookup(R)) + if (const BindingVal *BV = Lookup(B, R)) return Optional<SVal>::create(BV->getValue()); return Optional<SVal>(); @@ -1051,22 +1103,46 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) { if (const FieldRegion* FR = dyn_cast<FieldRegion>(R)) return SValuator::CastResult(state, - CastRetrievedVal(RetrieveField(state, FR), FR, T)); - - if (const ElementRegion* ER = dyn_cast<ElementRegion>(R)) + CastRetrievedVal(RetrieveField(state, FR), FR, + T, false)); + + if (const ElementRegion* ER = dyn_cast<ElementRegion>(R)) { + // FIXME: Here we actually perform an implicit conversion from the loaded + // value to the element type. Eventually we want to compose these values + // more intelligently. For example, an 'element' can encompass multiple + // bound regions (e.g., several bound bytes), or could be a subset of + // a larger value. return SValuator::CastResult(state, - CastRetrievedVal(RetrieveElement(state, ER), ER, T)); - - if (const ObjCIvarRegion *IVR = dyn_cast<ObjCIvarRegion>(R)) + CastRetrievedVal(RetrieveElement(state, ER), + ER, T, false)); + } + + if (const ObjCIvarRegion *IVR = dyn_cast<ObjCIvarRegion>(R)) { + // FIXME: Here we actually perform an implicit conversion from the loaded + // value to the ivar type. What we should model is stores to ivars + // that blow past the extent of the ivar. If the address of the ivar is + // reinterpretted, it is possible we stored a different value that could + // fit within the ivar. Either we need to cast these when storing them + // or reinterpret them lazily (as we do here). return SValuator::CastResult(state, - CastRetrievedVal(RetrieveObjCIvar(state, IVR), IVR, T)); + CastRetrievedVal(RetrieveObjCIvar(state, IVR), + IVR, T, false)); + } - if (const VarRegion *VR = dyn_cast<VarRegion>(R)) + if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { + // FIXME: Here we actually perform an implicit conversion from the loaded + // value to the variable type. What we should model is stores to variables + // that blow past the extent of the variable. If the address of the + // variable is reinterpretted, it is possible we stored a different value + // that could fit within the variable. Either we need to cast these when + // storing them or reinterpret them lazily (as we do here). return SValuator::CastResult(state, - CastRetrievedVal(RetrieveVar(state, VR), VR, T)); + CastRetrievedVal(RetrieveVar(state, VR), VR, T, + false)); + } RegionBindings B = GetRegionBindings(state->getStore()); - RegionBindings::data_type* V = B.lookup(R); + const BindingVal *V = Lookup(B, R); // Check if the region has a binding. if (V) @@ -1076,12 +1152,7 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) { // The location does not have a bound value. This means that it has // the value it had upon its creation and/or entry to the analyzed // function/method. These are either symbolic values or 'undefined'. - -#if HEAP_UNDEFINED - if (R->hasHeapOrStackStorage()) { -#else - if (R->hasStackStorage()) { -#endif + if (R->hasStackNonParametersStorage()) { // All stack variables are considered to have undefined values // upon creation. All heap allocated blocks are considered to // have undefined values as well unless they are explicitly bound @@ -1124,7 +1195,7 @@ SVal RegionStoreManager::RetrieveElement(const GRState* state, const ElementRegion* R) { // Check if the region has a binding. RegionBindings B = GetRegionBindings(state->getStore()); - if (Optional<SVal> V = getDirectBinding(B, R)) + if (Optional<SVal> V = getDirectBinding(B, R)) return *V; const MemRegion* superR = R->getSuperRegion(); @@ -1174,7 +1245,7 @@ SVal RegionStoreManager::RetrieveElement(const GRState* state, // Other cases: give up. return UnknownVal(); } - + return RetrieveFieldOrElementCommon(state, R, R->getElementType(), superR); } @@ -1240,8 +1311,7 @@ SVal RegionStoreManager::RetrieveFieldOrElementCommon(const GRState *state, cast<FieldRegion>(lazyBindingRegion)); } - if (R->hasStackStorage() && !R->hasParametersStorage()) { - + if (R->hasStackNonParametersStorage()) { if (isa<ElementRegion>(R)) { // Currently we don't reason specially about Clang-style vectors. Check // if superR is a vector and if so return Unknown. @@ -1369,15 +1439,9 @@ SVal RegionStoreManager::RetrieveArray(const GRState *state, //===----------------------------------------------------------------------===// Store RegionStoreManager::Remove(Store store, Loc L) { - const MemRegion* R = 0; - if (isa<loc::MemRegionVal>(L)) - R = cast<loc::MemRegionVal>(L).getRegion(); - - if (R) { - RegionBindings B = GetRegionBindings(store); - return RBFactory.Remove(B, R).getRoot(); - } + if (const MemRegion* R = cast<loc::MemRegionVal>(L).getRegion()) + return Remove(store, BindingKey::Make(R)); return store; } @@ -1436,8 +1500,8 @@ const GRState *RegionStoreManager::Bind(const GRState *state, Loc L, SVal V) { // Perform the binding. RegionBindings B = GetRegionBindings(state->getStore()); - return state->makeWithStore( - RBFactory.Add(B, R, BindingVal(V, BindingVal::Direct)).getRoot()); + return state->makeWithStore(Add(B, R, + BindingVal(V, BindingVal::Direct)).getRoot()); } const GRState *RegionStoreManager::BindDecl(const GRState *ST, @@ -1483,9 +1547,9 @@ const GRState *RegionStoreManager::setImplicitDefaultValue(const GRState *state, else { return state; } - - B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default)); - return state->makeWithStore(B.getRoot()); + + return state->makeWithStore(Add(B, R, + BindingVal(V, BindingVal::Default)).getRoot()); } const GRState *RegionStoreManager::BindArray(const GRState *state, @@ -1610,8 +1674,7 @@ RegionStoreManager::BindStruct(const GRState *state, const TypedRegion* R, if (FI != FE) { Store store = state->getStore(); RegionBindings B = GetRegionBindings(store); - B = RBFactory.Add(B, R, - BindingVal(ValMgr.makeIntVal(0, false), BindingVal::Default)); + B = Add(B, R, BindingVal(ValMgr.makeIntVal(0, false), BindingVal::Default)); state = state->makeWithStore(B.getRoot()); } @@ -1625,7 +1688,7 @@ Store RegionStoreManager::KillStruct(Store store, const TypedRegion* R) { RemoveSubRegionBindings(B, R, *SubRegions); // Set the default value of the struct region to "unknown". - B = RBFactory.Add(B, R, BindingVal(UnknownVal(), BindingVal::Default)); + B = Add(B, R, BindingVal(UnknownVal(), BindingVal::Default)); return B.getRoot(); } @@ -1646,8 +1709,58 @@ RegionStoreManager::CopyLazyBindings(nonloc::LazyCompoundVal V, // Now copy the bindings. This amounts to just binding 'V' to 'R'. This // results in a zero-copy algorithm. - return state->makeWithStore( - RBFactory.Add(B, R, BindingVal(V, BindingVal::Direct)).getRoot()); + return state->makeWithStore(Add(B, R, + BindingVal(V, BindingVal::Direct)).getRoot()); +} + +//===----------------------------------------------------------------------===// +// "Raw" retrievals and bindings. +//===----------------------------------------------------------------------===// + +BindingKey BindingKey::Make(const MemRegion *R) { + if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) { + const RegionRawOffset &O = ER->getAsRawOffset(); + + if (O.getRegion()) + return BindingKey(O.getRegion(), O.getByteOffset()); + + // FIXME: There are some ElementRegions for which we cannot compute + // raw offsets yet, including regions with symbolic offsets. + } + + return BindingKey(R, 0); +} + +RegionBindings RegionStoreManager::Add(RegionBindings B, BindingKey K, + BindingVal V) { + return RBFactory.Add(B, K, V); +} + +RegionBindings RegionStoreManager::Add(RegionBindings B, const MemRegion *R, + BindingVal V) { + return Add(B, BindingKey::Make(R), V); +} + +const BindingVal *RegionStoreManager::Lookup(RegionBindings B, BindingKey K) { + return B.lookup(K); +} + +const BindingVal *RegionStoreManager::Lookup(RegionBindings B, + const MemRegion *R) { + return Lookup(B, BindingKey::Make(R)); +} + +RegionBindings RegionStoreManager::Remove(RegionBindings B, BindingKey K) { + return RBFactory.Remove(B, K); +} + +RegionBindings RegionStoreManager::Remove(RegionBindings B, const MemRegion *R){ + return Remove(B, BindingKey::Make(R)); +} + +Store RegionStoreManager::Remove(Store store, BindingKey K) { + RegionBindings B = GetRegionBindings(store); + return Remove(B, K).getRoot(); } //===----------------------------------------------------------------------===// @@ -1674,7 +1787,7 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, // Scan the direct bindings for "intermediate" roots. for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) { - const MemRegion *R = I.getKey(); + const MemRegion *R = I.getKey().getRegion(); IntermediateRoots.push_back(R); } @@ -1831,13 +1944,13 @@ tryAgain: // as live. We now remove all the regions that are dead from the store // as well as update DSymbols with the set symbols that are now dead. for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) { - const MemRegion* R = I.getKey(); + const MemRegion* R = I.getKey().getRegion(); // If this region live? Is so, none of its symbols are dead. if (Visited.count(std::make_pair(&state, R))) continue; // Remove this dead region from the store. - store = Remove(store, ValMgr.makeLoc(R)); + store = Remove(store, I.getKey()); // Mark all non-live symbols that this region references as dead. if (const SymbolicRegion* SymR = dyn_cast<SymbolicRegion>(R)) diff --git a/lib/Analysis/ReturnStackAddressChecker.cpp b/lib/Analysis/ReturnStackAddressChecker.cpp index 3a6d8a4..4d7e8ad 100644 --- a/lib/Analysis/ReturnStackAddressChecker.cpp +++ b/lib/Analysis/ReturnStackAddressChecker.cpp @@ -67,6 +67,9 @@ void ReturnStackAddressChecker::PreVisitReturnStmt(CheckerContext &C, llvm::raw_svector_ostream os(buf); SourceRange range; + // Get the base region, stripping away fields and elements. + R = R->getBaseRegion(); + // Check if the region is a compound literal. if (const CompoundLiteralRegion* CR = dyn_cast<CompoundLiteralRegion>(R)) { const CompoundLiteralExpr* CL = CR->getLiteralExpr(); @@ -92,13 +95,18 @@ void ReturnStackAddressChecker::PreVisitReturnStmt(CheckerContext &C, << C.getSourceManager().getInstantiationLineNumber(L) << " returned to caller"; } - else { + else if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { os << "Address of stack memory associated with local variable '" - << R->getString() << "' returned."; + << VR->getString() << "' returned"; + range = VR->getDecl()->getSourceRange(); + } + else { + assert(false && "Invalid region in ReturnStackAddressChecker."); + return; } RangedBugReport *report = new RangedBugReport(*BT, os.str(), N); - report->addRange(RS->getSourceRange()); + report->addRange(RetE->getSourceRange()); if (range.isValid()) report->addRange(range); diff --git a/lib/Analysis/SVals.cpp b/lib/Analysis/SVals.cpp index 9163b27..fbdb73b 100644 --- a/lib/Analysis/SVals.cpp +++ b/lib/Analysis/SVals.cpp @@ -97,6 +97,10 @@ const MemRegion *SVal::getAsRegion() const { if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this)) return X->getRegion(); + if (const nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(this)) { + return X->getLoc().getAsRegion(); + } + return 0; } diff --git a/lib/Analysis/SValuator.cpp b/lib/Analysis/SValuator.cpp index 49bc0c4..8392fcf 100644 --- a/lib/Analysis/SValuator.cpp +++ b/lib/Analysis/SValuator.cpp @@ -62,8 +62,12 @@ SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state, ASTContext &C = ValMgr.getContext(); // For const casts, just propagate the value. - if (C.hasSameUnqualifiedType(castTy, originalTy)) - return CastResult(state, val); + if (!castTy->isVariableArrayType() && !originalTy->isVariableArrayType()) + if (C.hasSameUnqualifiedType(castTy, originalTy)) + return CastResult(state, val); + + if (castTy->isIntegerType() && originalTy->isIntegerType()) + return CastResult(state, EvalCastNL(cast<NonLoc>(val), castTy)); // Check for casts from pointers to integers. if (castTy->isIntegerType() && Loc::IsLocType(originalTy)) diff --git a/lib/Analysis/SimpleConstraintManager.cpp b/lib/Analysis/SimpleConstraintManager.cpp index 23c3b41..eca20d5 100644 --- a/lib/Analysis/SimpleConstraintManager.cpp +++ b/lib/Analysis/SimpleConstraintManager.cpp @@ -65,25 +65,10 @@ const GRState *SimpleConstraintManager::Assume(const GRState *state, return Assume(state, cast<Loc>(Cond), Assumption); } -const GRState *SimpleConstraintManager::Assume(const GRState *state, Loc Cond, - bool Assumption) { - - state = AssumeAux(state, Cond, Assumption); - - // EvalAssume is used to call into the GRTransferFunction object to perform - // any checker-specific update of the state based on this assumption being - // true or false. - - if (!state) - return 0; - - std::vector<std::pair<void *, Checker*> >::iterator - I = state->checker_begin(), E = state->checker_end(); - - for (; I != E; ++I) { - state = I->second->EvalAssume(state, Cond, Assumption); - } - return state->getTransferFuncs().EvalAssume(state, Cond, Assumption); +const GRState *SimpleConstraintManager::Assume(const GRState *state, Loc cond, + bool assumption) { + state = AssumeAux(state, cond, assumption); + return SU.ProcessAssume(state, cond, assumption); } const GRState *SimpleConstraintManager::AssumeAux(const GRState *state, @@ -130,26 +115,10 @@ const GRState *SimpleConstraintManager::AssumeAux(const GRState *state, } const GRState *SimpleConstraintManager::Assume(const GRState *state, - NonLoc Cond, - bool Assumption) { - - state = AssumeAux(state, Cond, Assumption); - - // EvalAssume is used to call into the GRTransferFunction object to perform - // any checker-specific update of the state based on this assumption being - // true or false. - - if (!state) - return 0; - - std::vector<std::pair<void *, Checker*> >::iterator - I = state->checker_begin(), E = state->checker_end(); - - for (; I != E; ++I) { - state = I->second->EvalAssume(state, Cond, Assumption); - } - - return state->getTransferFuncs().EvalAssume(state, Cond, Assumption); + NonLoc cond, + bool assumption) { + state = AssumeAux(state, cond, assumption); + return SU.ProcessAssume(state, cond, assumption); } const GRState *SimpleConstraintManager::AssumeAux(const GRState *state, diff --git a/lib/Analysis/SimpleConstraintManager.h b/lib/Analysis/SimpleConstraintManager.h index 0c58440..8182398 100644 --- a/lib/Analysis/SimpleConstraintManager.h +++ b/lib/Analysis/SimpleConstraintManager.h @@ -20,8 +20,9 @@ namespace clang { class SimpleConstraintManager : public ConstraintManager { + GRSubEngine &SU; public: - SimpleConstraintManager() {} + SimpleConstraintManager(GRSubEngine &subengine) : SU(subengine) {} virtual ~SimpleConstraintManager(); //===------------------------------------------------------------------===// diff --git a/lib/Analysis/SimpleSValuator.cpp b/lib/Analysis/SimpleSValuator.cpp index 2afcd3e..8f2f5a1 100644 --- a/lib/Analysis/SimpleSValuator.cpp +++ b/lib/Analysis/SimpleSValuator.cpp @@ -53,13 +53,13 @@ SVal SimpleSValuator::EvalCastNL(NonLoc val, QualType castTy) { if (isLocType) return LI->getLoc(); + // FIXME: Correctly support promotions/truncations. ASTContext &Ctx = ValMgr.getContext(); - - // FIXME: Support promotions/truncations. - if (Ctx.getTypeSize(castTy) == Ctx.getTypeSize(Ctx.VoidPtrTy)) + unsigned castSize = Ctx.getTypeSize(castTy); + if (castSize == LI->getNumBits()) return val; - return UnknownVal(); + return ValMgr.makeLocAsInteger(LI->getLoc(), castSize); } if (const SymExpr *se = val.getAsSymbolicExpression()) { diff --git a/lib/Analysis/Store.cpp b/lib/Analysis/Store.cpp index 8d911b8..1724a92 100644 --- a/lib/Analysis/Store.cpp +++ b/lib/Analysis/Store.cpp @@ -13,6 +13,7 @@ #include "clang/Analysis/PathSensitive/Store.h" #include "clang/Analysis/PathSensitive/GRState.h" +#include "clang/AST/CharUnits.h" using namespace clang; @@ -77,6 +78,7 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) // Process region cast according to the kind of the region being cast. switch (R->getKind()) { + case MemRegion::CXXThisRegionKind: case MemRegion::GenericMemSpaceRegionKind: case MemRegion::StackLocalsSpaceRegionKind: case MemRegion::StackArgumentsSpaceRegionKind: @@ -137,9 +139,9 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) if (!baseR) return NULL; - int64_t off = rawOff.getByteOffset(); + CharUnits off = CharUnits::fromQuantity(rawOff.getByteOffset()); - if (off == 0) { + if (off.isZero()) { // Edge case: we are at 0 bytes off the beginning of baseR. We // check to see if type we are casting to is the same as the base // region. If so, just return the base region. @@ -167,7 +169,7 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) // We can only compute sizeof(PointeeTy) if it is a complete type. if (IsCompleteType(Ctx, PointeeTy)) { // Compute the size in **bytes**. - int64_t pointeeTySize = (int64_t) (Ctx.getTypeSize(PointeeTy) / 8); + CharUnits pointeeTySize = Ctx.getTypeSizeInChars(PointeeTy); // Is the offset a multiple of the size? If so, we can layer the // ElementRegion (with elementType == PointeeTy) directly on top of @@ -181,7 +183,7 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) if (!newSuperR) { // Create an intermediate ElementRegion to represent the raw byte. // This will be the super region of the final ElementRegion. - newSuperR = MakeElementRegion(baseR, Ctx.CharTy, off); + newSuperR = MakeElementRegion(baseR, Ctx.CharTy, off.getQuantity()); } return MakeElementRegion(newSuperR, PointeeTy, newIndex); @@ -196,23 +198,29 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) /// CastRetrievedVal - Used by subclasses of StoreManager to implement /// implicit casts that arise from loads from regions that are reinterpreted /// as another region. -SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R, - QualType castTy) { +SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R, + QualType castTy, bool performTestOnly) { -#ifndef NDEBUG if (castTy.isNull()) return V; ASTContext &Ctx = ValMgr.getContext(); - QualType T = R->getValueType(Ctx); - - // Automatically translate references to pointers. - if (const ReferenceType *RT = T->getAs<ReferenceType>()) - T = Ctx.getPointerType(RT->getPointeeType()); - - assert(ValMgr.getContext().hasSameUnqualifiedType(castTy, T)); -#endif + if (performTestOnly) { + // Automatically translate references to pointers. + QualType T = R->getValueType(Ctx); + if (const ReferenceType *RT = T->getAs<ReferenceType>()) + T = Ctx.getPointerType(RT->getPointeeType()); + + assert(ValMgr.getContext().hasSameUnqualifiedType(castTy, T)); + return V; + } + + if (const Loc *L = dyn_cast<Loc>(&V)) + return ValMgr.getSValuator().EvalCastL(*L, castTy); + else if (const NonLoc *NL = dyn_cast<NonLoc>(&V)) + return ValMgr.getSValuator().EvalCastNL(*NL, castTy); + return V; } @@ -240,8 +248,3 @@ SVal StoreManager::getLValueCompoundLiteral(const CompoundLiteralExpr* CL, const LocationContext *LC) { return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC)); } - -Loc StoreManager::getThisObject(QualType T) { - const CXXObjectRegion *R = MRMgr.getCXXObjectRegion(T); - return loc::MemRegionVal(R); -} |