diff options
author | rdivacky <rdivacky@FreeBSD.org> | 2010-03-03 17:28:16 +0000 |
---|---|---|
committer | rdivacky <rdivacky@FreeBSD.org> | 2010-03-03 17:28:16 +0000 |
commit | df90325d4c0a65ee64d2dae3ed9b5b34f7418533 (patch) | |
tree | e1a885aadfd80632f5bd70d4bd2d37e715e35a79 /lib/Checker | |
parent | fd035e6496665b1f1197868e21cb0a4594e8db6e (diff) | |
download | FreeBSD-src-df90325d4c0a65ee64d2dae3ed9b5b34f7418533.zip FreeBSD-src-df90325d4c0a65ee64d2dae3ed9b5b34f7418533.tar.gz |
Update clang to 97654.
Diffstat (limited to 'lib/Checker')
-rw-r--r-- | lib/Checker/BasicStore.cpp | 52 | ||||
-rw-r--r-- | lib/Checker/BuiltinFunctionChecker.cpp | 1 | ||||
-rw-r--r-- | lib/Checker/CFRefCount.cpp | 40 | ||||
-rw-r--r-- | lib/Checker/CMakeLists.txt | 4 | ||||
-rw-r--r-- | lib/Checker/CallInliner.cpp | 67 | ||||
-rw-r--r-- | lib/Checker/CheckDeadStores.cpp | 3 | ||||
-rw-r--r-- | lib/Checker/FlatStore.cpp | 2 | ||||
-rw-r--r-- | lib/Checker/GRCoreEngine.cpp | 104 | ||||
-rw-r--r-- | lib/Checker/GRExprEngine.cpp | 70 | ||||
-rw-r--r-- | lib/Checker/GRExprEngineInternalChecks.h | 30 | ||||
-rw-r--r-- | lib/Checker/MacOSXAPIChecker.cpp | 141 | ||||
-rw-r--r-- | lib/Checker/MemRegion.cpp | 25 | ||||
-rw-r--r-- | lib/Checker/OSAtomicChecker.cpp | 1 | ||||
-rw-r--r-- | lib/Checker/ObjCUnusedIVarsChecker.cpp (renamed from lib/Checker/CheckObjCUnusedIVars.cpp) | 29 | ||||
-rw-r--r-- | lib/Checker/RegionStore.cpp | 14 | ||||
-rw-r--r-- | lib/Checker/SymbolManager.cpp | 21 | ||||
-rw-r--r-- | lib/Checker/UnixAPIChecker.cpp | 154 | ||||
-rw-r--r-- | lib/Checker/ValueManager.cpp | 12 |
18 files changed, 597 insertions, 173 deletions
diff --git a/lib/Checker/BasicStore.cpp b/lib/Checker/BasicStore.cpp index 6ef2942..d93a665 100644 --- a/lib/Checker/BasicStore.cpp +++ b/lib/Checker/BasicStore.cpp @@ -95,6 +95,8 @@ public: const char *sep); private: + SVal LazyRetrieve(Store store, const TypedRegion *R); + ASTContext& getContext() { return StateMgr.getContext(); } }; @@ -126,6 +128,25 @@ static bool isHigherOrderRawPtr(QualType T, ASTContext &C) { } } +SVal BasicStoreManager::LazyRetrieve(Store store, const TypedRegion *R) { + const VarRegion *VR = dyn_cast<VarRegion>(R); + if (!VR) + return UnknownVal(); + + const VarDecl *VD = VR->getDecl(); + QualType T = VD->getType(); + + // Only handle simple types that we can symbolicate. + if (!SymbolManager::canSymbolicate(T) || !T->isScalarType()) + return UnknownVal(); + + // Globals and parameters start with symbolic values. + // Local variables initially are undefined. + if (VR->hasGlobalsOrParametersStorage()) + return ValMgr.getRegionValueSymbolVal(R); + return UndefinedVal(); +} + SVal BasicStoreManager::Retrieve(Store store, Loc loc, QualType T) { if (isa<UnknownVal>(loc)) return UnknownVal(); @@ -142,11 +163,13 @@ SVal BasicStoreManager::Retrieve(Store store, Loc loc, QualType T) { BindingsTy B = GetBindings(store); BindingsTy::data_type *Val = B.lookup(R); + const TypedRegion *TR = cast<TypedRegion>(R); - if (!Val) - break; + if (Val) + return CastRetrievedVal(*Val, TR, T); - return CastRetrievedVal(*Val, cast<TypedRegion>(R), T); + SVal V = LazyRetrieve(store, TR); + return V.isUnknownOrUndef() ? V : CastRetrievedVal(V, TR, T); } case loc::ConcreteIntKind: @@ -319,7 +342,7 @@ Store BasicStoreManager::scanForIvars(Stmt *B, const Decl* SelfDecl, const Expr *Base = IV->getBase()->IgnoreParenCasts(); if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Base)) { if (DR->getDecl() == SelfDecl) { - const MemRegion *IVR = MRMgr.getObjCIvarRegion(IV->getDecl(), + const ObjCIvarRegion *IVR = MRMgr.getObjCIvarRegion(IV->getDecl(), SelfRegion); SVal X = ValMgr.getRegionValueSymbolVal(IVR); St = Bind(St, ValMgr.makeLoc(IVR), X); @@ -351,10 +374,10 @@ Store BasicStoreManager::getInitialStore(const LocationContext *InitLoc) { if (MD->getSelfDecl() == PD) { // FIXME: Add type constraints (when they become available) to // SelfRegion? (i.e., it implements MD->getClassInterface()). - const MemRegion *VR = MRMgr.getVarRegion(PD, InitLoc); + const VarRegion *VR = MRMgr.getVarRegion(PD, InitLoc); const MemRegion *SelfRegion = - ValMgr.getRegionValueSymbolVal(VR).getAsRegion(); - assert(SelfRegion); + ValMgr.getRegionValueSymbolVal(VR).getAsRegion(); + assert(SelfRegion); St = Bind(St, ValMgr.makeLoc(VR), loc::MemRegionVal(SelfRegion)); // Scan the method for ivar references. While this requires an // entire AST scan, the cost should not be high in practice. @@ -362,21 +385,8 @@ Store BasicStoreManager::getInitialStore(const LocationContext *InitLoc) { } } } - else if (VarDecl* VD = dyn_cast<VarDecl>(ND)) { - // Only handle simple types that we can symbolicate. - if (!SymbolManager::canSymbolicate(VD->getType())) - continue; - - // Initialize globals and parameters to symbolic values. - // Initialize local variables to undefined. - const MemRegion *R = ValMgr.getRegionManager().getVarRegion(VD, InitLoc); - SVal X = UndefinedVal(); - if (R->hasGlobalsOrParametersStorage()) - X = ValMgr.getRegionValueSymbolVal(R); - - St = Bind(St, ValMgr.makeLoc(R), X); - } } + return St; } diff --git a/lib/Checker/BuiltinFunctionChecker.cpp b/lib/Checker/BuiltinFunctionChecker.cpp index 8711492..9c8b516 100644 --- a/lib/Checker/BuiltinFunctionChecker.cpp +++ b/lib/Checker/BuiltinFunctionChecker.cpp @@ -14,7 +14,6 @@ #include "GRExprEngineInternalChecks.h" #include "clang/Checker/PathSensitive/Checker.h" #include "clang/Basic/Builtins.h" -#include "llvm/ADT/StringSwitch.h" using namespace clang; diff --git a/lib/Checker/CFRefCount.cpp b/lib/Checker/CFRefCount.cpp index 324916a..ecb98a0 100644 --- a/lib/Checker/CFRefCount.cpp +++ b/lib/Checker/CFRefCount.cpp @@ -12,26 +12,26 @@ // //===----------------------------------------------------------------------===// +#include "clang/AST/DeclObjC.h" +#include "clang/AST/StmtVisitor.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/SourceManager.h" -#include "clang/Checker/PathSensitive/GRExprEngineBuilders.h" -#include "clang/Checker/PathSensitive/GRStateTrait.h" +#include "clang/Checker/BugReporter/BugReporter.h" #include "clang/Checker/BugReporter/PathDiagnostic.h" -#include "clang/Checker/Checkers/LocalCheckers.h" #include "clang/Checker/BugReporter/PathDiagnostic.h" -#include "clang/Checker/BugReporter/BugReporter.h" -#include "clang/Checker/PathSensitive/SymbolManager.h" -#include "clang/Checker/PathSensitive/GRTransferFuncs.h" -#include "clang/Checker/PathSensitive/CheckerVisitor.h" +#include "clang/Checker/Checkers/LocalCheckers.h" #include "clang/Checker/DomainSpecific/CocoaConventions.h" -#include "clang/AST/DeclObjC.h" -#include "clang/AST/StmtVisitor.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" +#include "clang/Checker/PathSensitive/GRExprEngineBuilders.h" +#include "clang/Checker/PathSensitive/GRStateTrait.h" +#include "clang/Checker/PathSensitive/GRTransferFuncs.h" +#include "clang/Checker/PathSensitive/SymbolManager.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" -#include "llvm/ADT/ImmutableMap.h" #include "llvm/ADT/ImmutableList.h" -#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/ImmutableMap.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" #include <stdarg.h> using namespace clang; @@ -1222,6 +1222,12 @@ RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ, else if (FD->getAttr<CFReturnsRetainedAttr>()) { Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true)); } + else if (FD->getAttr<NSReturnsNotRetainedAttr>()) { + Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::ObjC)); + } + else if (FD->getAttr<CFReturnsNotRetainedAttr>()) { + Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF)); + } } else if (RetTy->getAs<PointerType>()) { if (FD->getAttr<CFReturnsRetainedAttr>()) { @@ -1244,6 +1250,10 @@ RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ, Summ.setRetEffect(ObjCAllocRetE); return; } + if (MD->getAttr<NSReturnsNotRetainedAttr>()) { + Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::ObjC)); + return; + } isTrackedLoc = true; } @@ -1251,8 +1261,12 @@ RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ, if (!isTrackedLoc) isTrackedLoc = MD->getResultType()->getAs<PointerType>() != NULL; - if (isTrackedLoc && MD->getAttr<CFReturnsRetainedAttr>()) - Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true)); + if (isTrackedLoc) { + if (MD->getAttr<CFReturnsRetainedAttr>()) + Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true)); + else if (MD->getAttr<CFReturnsNotRetainedAttr>()) + Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF)); + } } RetainSummary* diff --git a/lib/Checker/CMakeLists.txt b/lib/Checker/CMakeLists.txt index 7b21d08..c5bd2eb 100644 --- a/lib/Checker/CMakeLists.txt +++ b/lib/Checker/CMakeLists.txt @@ -18,7 +18,6 @@ add_clang_library(clangChecker CheckDeadStores.cpp CheckObjCDealloc.cpp CheckObjCInstMethSignature.cpp - CheckObjCUnusedIVars.cpp CheckSecuritySyntaxOnly.cpp CheckSizeofPointer.cpp Checker.cpp @@ -35,6 +34,7 @@ add_clang_library(clangChecker GRExprEngineExperimentalChecks.cpp GRState.cpp LLVMConventionsChecker.cpp + MacOSXAPIChecker.cpp MallocChecker.cpp ManagerRegistry.cpp MemRegion.cpp @@ -42,6 +42,7 @@ add_clang_library(clangChecker NSErrorChecker.cpp NoReturnFunctionChecker.cpp OSAtomicChecker.cpp + ObjCUnusedIVarsChecker.cpp PathDiagnostic.cpp PointerArithChecker.cpp PointerSubChecker.cpp @@ -62,6 +63,7 @@ add_clang_library(clangChecker UndefResultChecker.cpp UndefinedArraySubscriptChecker.cpp UndefinedAssignmentChecker.cpp + UnixAPIChecker.cpp VLASizeChecker.cpp ValueManager.cpp ) diff --git a/lib/Checker/CallInliner.cpp b/lib/Checker/CallInliner.cpp index d94994b..88e1a05 100644 --- a/lib/Checker/CallInliner.cpp +++ b/lib/Checker/CallInliner.cpp @@ -26,7 +26,6 @@ public: } virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE); - virtual void EvalEndPath(GREndPathNodeBuilder &B,void *tag,GRExprEngine &Eng); }; } @@ -43,71 +42,13 @@ bool CallInliner::EvalCallExpr(CheckerContext &C, const CallExpr *CE) { if (!FD) return false; - if (!FD->isThisDeclarationADefinition()) + if (!FD->getBody(FD)) return false; - GRStmtNodeBuilder &Builder = C.getNodeBuilder(); - // Make a new LocationContext. - const StackFrameContext *LocCtx = C.getAnalysisManager().getStackFrame(FD, - C.getPredecessor()->getLocationContext(), CE, - Builder.getBlock(), Builder.getIndex()); - - CFGBlock const *Entry = &(LocCtx->getCFG()->getEntry()); - - assert (Entry->empty() && "Entry block must be empty."); - - assert (Entry->succ_size() == 1 && "Entry block must have 1 successor."); - - // Get the solitary successor. - CFGBlock const *SuccB = *(Entry->succ_begin()); - - // Construct an edge representing the starting location in the function. - BlockEdge Loc(Entry, SuccB, LocCtx); - - state = C.getStoreManager().EnterStackFrame(state, LocCtx); - // This is a hack. We really should not use the GRStmtNodeBuilder. - bool isNew; - GRExprEngine &Eng = C.getEngine(); - ExplodedNode *Pred = C.getPredecessor(); - - - ExplodedNode *SuccN = Eng.getGraph().getNode(Loc, state, &isNew); - SuccN->addPredecessor(Pred, Eng.getGraph()); - C.getNodeBuilder().Deferred.erase(Pred); - - if (isNew) - Builder.getWorkList()->Enqueue(SuccN); - - Builder.HasGeneratedNode = true; + // Now we have the definition of the callee, create a CallEnter node. + CallEnter Loc(CE, FD, C.getPredecessor()->getLocationContext()); + C.addTransition(state, Loc); return true; } -void CallInliner::EvalEndPath(GREndPathNodeBuilder &B, void *tag, - GRExprEngine &Eng) { - const GRState *state = B.getState(); - ExplodedNode *Pred = B.getPredecessor(); - const StackFrameContext *LocCtx = - cast<StackFrameContext>(Pred->getLocationContext()); - - const Stmt *CE = LocCtx->getCallSite(); - - // Check if this is the top level stack frame. - if (!LocCtx->getParent()) - return; - - PostStmt NodeLoc(CE, LocCtx->getParent()); - - bool isNew; - ExplodedNode *Succ = Eng.getGraph().getNode(NodeLoc, state, &isNew); - Succ->addPredecessor(Pred, Eng.getGraph()); - - // When creating the new work list unit, increment the statement index to - // point to the statement after the CallExpr. - if (isNew) - B.getWorkList().Enqueue(Succ, - *const_cast<CFGBlock*>(LocCtx->getCallSiteBlock()), - LocCtx->getIndex() + 1); - - B.HasGeneratedNode = true; -} diff --git a/lib/Checker/CheckDeadStores.cpp b/lib/Checker/CheckDeadStores.cpp index 4a7ca70..31f9390 100644 --- a/lib/Checker/CheckDeadStores.cpp +++ b/lib/Checker/CheckDeadStores.cpp @@ -142,7 +142,8 @@ public: if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { // Special case: check for assigning null to a pointer. // This is a common form of defensive programming. - if (VD->getType()->isPointerType()) { + QualType T = VD->getType(); + if (T->isPointerType() || T->isObjCObjectPointerType()) { if (B->getRHS()->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNull)) return; diff --git a/lib/Checker/FlatStore.cpp b/lib/Checker/FlatStore.cpp index dac66de..07a54fb 100644 --- a/lib/Checker/FlatStore.cpp +++ b/lib/Checker/FlatStore.cpp @@ -97,7 +97,7 @@ SVal FlatStoreManager::RetrieveRegionWithNoBinding(const MemRegion *R, if (R->hasStackNonParametersStorage()) return UndefinedVal(); else - return ValMgr.getRegionValueSymbolVal(R, T); + return ValMgr.getRegionValueSymbolVal(cast<TypedRegion>(R)); } Store FlatStoreManager::Bind(Store store, Loc L, SVal val) { diff --git a/lib/Checker/GRCoreEngine.cpp b/lib/Checker/GRCoreEngine.cpp index d54b077..a9347d0 100644 --- a/lib/Checker/GRCoreEngine.cpp +++ b/lib/Checker/GRCoreEngine.cpp @@ -144,6 +144,14 @@ void GRCoreEngine::ProcessSwitch(GRSwitchNodeBuilder& Builder) { SubEngine.ProcessSwitch(Builder); } +void GRCoreEngine::ProcessCallEnter(GRCallEnterNodeBuilder &Builder) { + SubEngine.ProcessCallEnter(Builder); +} + +void GRCoreEngine::ProcessCallExit(GRCallExitNodeBuilder &Builder) { + SubEngine.ProcessCallExit(Builder); +} + /// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps. bool GRCoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps) { @@ -196,6 +204,15 @@ bool GRCoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps) { assert (false && "BlockExit location never occur in forward analysis."); break; + case ProgramPoint::CallEnterKind: + HandleCallEnter(cast<CallEnter>(Node->getLocation()), WU.getBlock(), + WU.getIndex(), Node); + break; + + case ProgramPoint::CallExitKind: + HandleCallExit(cast<CallExit>(Node->getLocation()), Node); + break; + default: assert(isa<PostStmt>(Node->getLocation())); HandlePostStmt(cast<PostStmt>(Node->getLocation()), WU.getBlock(), @@ -207,6 +224,17 @@ bool GRCoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps) { return WList->hasWork(); } +void GRCoreEngine::HandleCallEnter(const CallEnter &L, const CFGBlock *Block, + unsigned Index, ExplodedNode *Pred) { + GRCallEnterNodeBuilder Builder(*this, Pred, L.getCallExpr(), L.getCallee(), + Block, Index); + ProcessCallEnter(Builder); +} + +void GRCoreEngine::HandleCallExit(const CallExit &L, ExplodedNode *Pred) { + GRCallExitNodeBuilder Builder(*this, Pred); + ProcessCallExit(Builder); +} void GRCoreEngine::HandleBlockEdge(const BlockEdge& L, ExplodedNode* Pred) { @@ -384,11 +412,11 @@ void GRCoreEngine::GenerateNode(const ProgramPoint& Loc, GRStmtNodeBuilder::GRStmtNodeBuilder(CFGBlock* b, unsigned idx, ExplodedNode* N, GRCoreEngine* e, GRStateManager &mgr) - : Eng(*e), B(*b), Idx(idx), Pred(N), LastNode(N), Mgr(mgr), Auditor(0), + : Eng(*e), B(*b), Idx(idx), Pred(N), Mgr(mgr), Auditor(0), PurgingDeadSymbols(false), BuildSinks(false), HasGeneratedNode(false), PointKind(ProgramPoint::PostStmtKind), Tag(0) { Deferred.insert(N); - CleanedState = getLastNode()->getState(); + CleanedState = Pred->getState(); } GRStmtNodeBuilder::~GRStmtNodeBuilder() { @@ -400,6 +428,14 @@ GRStmtNodeBuilder::~GRStmtNodeBuilder() { void GRStmtNodeBuilder::GenerateAutoTransition(ExplodedNode* N) { assert (!N->isSink()); + // Check if this node entered a callee. + if (isa<CallEnter>(N->getLocation())) { + // Still use the index of the CallExpr. It's needed to create the callee + // StackFrameContext. + Eng.WList->Enqueue(N, B, Idx); + return; + } + PostStmt Loc(getStmt(), N->getLocationContext()); if (Loc == N->getLocation()) { @@ -462,11 +498,9 @@ GRStmtNodeBuilder::generateNodeInternal(const ProgramPoint &Loc, if (IsNew) { Deferred.insert(N); - LastNode = N; return N; } - LastNode = NULL; return NULL; } @@ -576,7 +610,13 @@ GRSwitchNodeBuilder::generateDefaultCaseNode(const GRState* St, bool isSink) { GREndPathNodeBuilder::~GREndPathNodeBuilder() { // Auto-generate an EOP node if one has not been generated. - if (!HasGeneratedNode) generateNode(Pred->State); + if (!HasGeneratedNode) { + // If we are in an inlined call, generate CallExit node. + if (Pred->getLocationContext()->getParent()) + GenerateCallExitNode(Pred->State); + else + generateNode(Pred->State); + } } ExplodedNode* @@ -597,3 +637,57 @@ GREndPathNodeBuilder::generateNode(const GRState* State, const void *tag, return NULL; } + +void GREndPathNodeBuilder::GenerateCallExitNode(const GRState *state) { + HasGeneratedNode = true; + // Create a CallExit node and enqueue it. + const StackFrameContext *LocCtx + = cast<StackFrameContext>(Pred->getLocationContext()); + const Stmt *CE = LocCtx->getCallSite(); + + // Use the the callee location context. + CallExit Loc(CE, LocCtx); + + bool isNew; + ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew); + Node->addPredecessor(Pred, *Eng.G); + + if (isNew) + Eng.WList->Enqueue(Node); +} + + +void GRCallEnterNodeBuilder::GenerateNode(const GRState *state, + const LocationContext *LocCtx) { + // Get the callee entry block. + const CFGBlock *Entry = &(LocCtx->getCFG()->getEntry()); + assert(Entry->empty()); + assert(Entry->succ_size() == 1); + + // Get the solitary successor. + const CFGBlock *SuccB = *(Entry->succ_begin()); + + // Construct an edge representing the starting location in the callee. + BlockEdge Loc(Entry, SuccB, LocCtx); + + bool isNew; + ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew); + Node->addPredecessor(const_cast<ExplodedNode*>(Pred), *Eng.G); + + if (isNew) + Eng.WList->Enqueue(Node); +} + +void GRCallExitNodeBuilder::GenerateNode(const GRState *state) { + // Get the callee's location context. + const StackFrameContext *LocCtx + = cast<StackFrameContext>(Pred->getLocationContext()); + + PostStmt Loc(LocCtx->getCallSite(), LocCtx->getParent()); + bool isNew; + ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew); + Node->addPredecessor(const_cast<ExplodedNode*>(Pred), *Eng.G); + if (isNew) + Eng.WList->Enqueue(Node, *const_cast<CFGBlock*>(LocCtx->getCallSiteBlock()), + LocCtx->getIndex() + 1); +} diff --git a/lib/Checker/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp index 7f86319..ad229c7 100644 --- a/lib/Checker/GRExprEngine.cpp +++ b/lib/Checker/GRExprEngine.cpp @@ -37,6 +37,15 @@ using llvm::dyn_cast_or_null; using llvm::cast; using llvm::APSInt; +namespace { + // Trait class for recording returned expression in the state. + struct ReturnExpr { + static int TagInt; + typedef const Stmt *data_type; + }; + int ReturnExpr::TagInt; +} + //===----------------------------------------------------------------------===// // Utility functions. //===----------------------------------------------------------------------===// @@ -318,6 +327,8 @@ static void RegisterInternalChecks(GRExprEngine &Eng) { RegisterNoReturnFunctionChecker(Eng); RegisterBuiltinFunctionChecker(Eng); RegisterOSAtomicChecker(Eng); + RegisterUnixAPIChecker(Eng); + RegisterMacOSXAPIChecker(Eng); } GRExprEngine::GRExprEngine(AnalysisManager &mgr, GRTransferFuncs *tf) @@ -458,7 +469,7 @@ void GRExprEngine::ProcessStmt(CFGElement CE, GRStmtNodeBuilder& builder) { "Error evaluating statement"); Builder = &builder; - EntryNode = builder.getLastNode(); + EntryNode = builder.getBasePredecessor(); // Set up our simple checks. if (BatchAuditor) @@ -1288,6 +1299,37 @@ void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) { if (defaultIsFeasible) builder.generateDefaultCaseNode(DefaultSt); } +void GRExprEngine::ProcessCallEnter(GRCallEnterNodeBuilder &B) { + const FunctionDecl *FD = B.getCallee(); + const StackFrameContext *LocCtx = AMgr.getStackFrame(FD, + B.getLocationContext(), + B.getCallExpr(), + B.getBlock(), + B.getIndex()); + + const GRState *state = B.getState(); + state = getStoreManager().EnterStackFrame(state, LocCtx); + + B.GenerateNode(state, LocCtx); +} + +void GRExprEngine::ProcessCallExit(GRCallExitNodeBuilder &B) { + const GRState *state = B.getState(); + const ExplodedNode *Pred = B.getPredecessor(); + const StackFrameContext *LocCtx = + cast<StackFrameContext>(Pred->getLocationContext()); + const Stmt *CE = LocCtx->getCallSite(); + + // If the callee returns an expression, bind its value to CallExpr. + const Stmt *ReturnedExpr = state->get<ReturnExpr>(); + if (ReturnedExpr) { + SVal RetVal = state->getSVal(ReturnedExpr); + state = state->BindExpr(CE, RetVal); + } + + B.GenerateNode(state); +} + //===----------------------------------------------------------------------===// // Transfer functions: logical operations ('&&', '||'). //===----------------------------------------------------------------------===// @@ -2316,8 +2358,9 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred, // Recover some path-sensitivity if a scalar value evaluated to // UnknownVal. - if (InitVal.isUnknown() || - !getConstraintManager().canReasonAbout(InitVal)) { + if ((InitVal.isUnknown() || + !getConstraintManager().canReasonAbout(InitVal)) && + !VD->getType()->isReferenceType()) { InitVal = ValMgr.getConjuredSymbolVal(NULL, InitEx, Builder->getCurrentBlockCount()); } @@ -2855,10 +2898,19 @@ void GRExprEngine::VisitAsmStmtHelperInputs(AsmStmt* A, void GRExprEngine::VisitReturnStmt(ReturnStmt *RS, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - ExplodedNodeSet Src; if (Expr *RetE = RS->getRetValue()) { - Visit(RetE, Pred, Src); + // Record the returned expression in the state. + { + static int Tag = 0; + SaveAndRestore<const void *> OldTag(Builder->Tag, &Tag); + const GRState *state = GetState(Pred); + state = state->set<ReturnExpr>(RetE); + Pred = Builder->generateNode(RetE, state, Pred); + } + // We may get a NULL Pred because we generated a cached node. + if (Pred) + Visit(RetE, Pred, Src); } else { Src.Add(Pred); @@ -3139,6 +3191,14 @@ struct DOTGraphTraits<ExplodedNode*> : assert (false); break; + case ProgramPoint::CallEnterKind: + Out << "CallEnter"; + break; + + case ProgramPoint::CallExitKind: + Out << "CallExit"; + break; + default: { if (StmtPoint *L = dyn_cast<StmtPoint>(&Loc)) { const Stmt* S = L->getStmt(); diff --git a/lib/Checker/GRExprEngineInternalChecks.h b/lib/Checker/GRExprEngineInternalChecks.h index 64a930d..d117600 100644 --- a/lib/Checker/GRExprEngineInternalChecks.h +++ b/lib/Checker/GRExprEngineInternalChecks.h @@ -19,27 +19,33 @@ namespace clang { class GRExprEngine; +// Foundational checks that handle basic semantics. void RegisterAdjustedReturnValueChecker(GRExprEngine &Eng); +void RegisterArrayBoundChecker(GRExprEngine &Eng); void RegisterAttrNonNullChecker(GRExprEngine &Eng); +void RegisterBuiltinFunctionChecker(GRExprEngine &Eng); +void RegisterCallAndMessageChecker(GRExprEngine &Eng); +void RegisterCastToStructChecker(GRExprEngine &Eng); void RegisterDereferenceChecker(GRExprEngine &Eng); void RegisterDivZeroChecker(GRExprEngine &Eng); +void RegisterFixedAddressChecker(GRExprEngine &Eng); +void RegisterNoReturnFunctionChecker(GRExprEngine &Eng); +void RegisterPointerArithChecker(GRExprEngine &Eng); +void RegisterPointerSubChecker(GRExprEngine &Eng); void RegisterReturnPointerRangeChecker(GRExprEngine &Eng); -void RegisterReturnStackAddressChecker(GRExprEngine &Eng); +void RegisterReturnStackAddressChecker(GRExprEngine &Eng); void RegisterReturnUndefChecker(GRExprEngine &Eng); -void RegisterVLASizeChecker(GRExprEngine &Eng); -void RegisterPointerSubChecker(GRExprEngine &Eng); -void RegisterPointerArithChecker(GRExprEngine &Eng); -void RegisterFixedAddressChecker(GRExprEngine &Eng); -void RegisterCastToStructChecker(GRExprEngine &Eng); -void RegisterCallAndMessageChecker(GRExprEngine &Eng); -void RegisterArrayBoundChecker(GRExprEngine &Eng); -void RegisterUndefinedArraySubscriptChecker(GRExprEngine &Eng); -void RegisterUndefinedAssignmentChecker(GRExprEngine &Eng); void RegisterUndefBranchChecker(GRExprEngine &Eng); void RegisterUndefCapturedBlockVarChecker(GRExprEngine &Eng); void RegisterUndefResultChecker(GRExprEngine &Eng); -void RegisterNoReturnFunctionChecker(GRExprEngine &Eng); -void RegisterBuiltinFunctionChecker(GRExprEngine &Eng); +void RegisterUndefinedArraySubscriptChecker(GRExprEngine &Eng); +void RegisterUndefinedAssignmentChecker(GRExprEngine &Eng); +void RegisterVLASizeChecker(GRExprEngine &Eng); + +// API checks. +void RegisterMacOSXAPIChecker(GRExprEngine &Eng); void RegisterOSAtomicChecker(GRExprEngine &Eng); +void RegisterUnixAPIChecker(GRExprEngine &Eng); + } // end clang namespace #endif diff --git a/lib/Checker/MacOSXAPIChecker.cpp b/lib/Checker/MacOSXAPIChecker.cpp new file mode 100644 index 0000000..9621e85 --- /dev/null +++ b/lib/Checker/MacOSXAPIChecker.cpp @@ -0,0 +1,141 @@ +// MacOSXAPIChecker.h - Checks proper use of various MacOS X APIs --*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines MacOSXAPIChecker, which is an assortment of checks on calls +// to various, widely used Mac OS X functions. +// +// FIXME: What's currently in BasicObjCFoundationChecks.cpp should be migrated +// to here, using the new Checker interface. +// +//===----------------------------------------------------------------------===// + +#include "GRExprEngineInternalChecks.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" +#include "clang/Checker/PathSensitive/GRStateTrait.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; + +namespace { +class MacOSXAPIChecker : public CheckerVisitor<MacOSXAPIChecker> { + enum SubChecks { + DispatchOnce = 0, + DispatchOnceF, + NumChecks + }; + + BugType *BTypes[NumChecks]; + +public: + MacOSXAPIChecker() { memset(BTypes, 0, sizeof(*BTypes) * NumChecks); } + static void *getTag() { static unsigned tag = 0; return &tag; } + + void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE); +}; +} //end anonymous namespace + +void clang::RegisterMacOSXAPIChecker(GRExprEngine &Eng) { + if (Eng.getContext().Target.getTriple().getVendor() == llvm::Triple::Apple) + Eng.registerCheck(new MacOSXAPIChecker()); +} + +//===----------------------------------------------------------------------===// +// dispatch_once and dispatch_once_f +//===----------------------------------------------------------------------===// + +static void CheckDispatchOnce(CheckerContext &C, const CallExpr *CE, + BugType *&BT, const IdentifierInfo *FI) { + + if (!BT) { + llvm::SmallString<128> S; + llvm::raw_svector_ostream os(S); + os << "Improper use of '" << FI->getName() << '\''; + BT = new BugType(os.str(), "Mac OS X API"); + } + + if (CE->getNumArgs() < 1) + return; + + // Check if the first argument is stack allocated. If so, issue a warning + // because that's likely to be bad news. + const GRState *state = C.getState(); + const MemRegion *R = state->getSVal(CE->getArg(0)).getAsRegion(); + if (!R || !isa<StackSpaceRegion>(R->getMemorySpace())) + return; + + ExplodedNode *N = C.GenerateSink(state); + if (!N) + return; + + llvm::SmallString<256> S; + llvm::raw_svector_ostream os(S); + os << "Call to '" << FI->getName() << "' uses"; + if (const VarRegion *VR = dyn_cast<VarRegion>(R)) + os << " the local variable '" << VR->getDecl()->getName() << '\''; + else + os << " stack allocated memory"; + os << " for the predicate value. Using such transient memory for " + "the predicate is potentially dangerous."; + if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace())) + os << " Perhaps you intended to declare the variable as 'static'?"; + + EnhancedBugReport *report = new EnhancedBugReport(*BT, os.str(), N); + report->addRange(CE->getArg(0)->getSourceRange()); + C.EmitReport(report); +} + +//===----------------------------------------------------------------------===// +// Central dispatch function. +//===----------------------------------------------------------------------===// + +typedef void (*SubChecker)(CheckerContext &C, const CallExpr *CE, BugType *&BT, + const IdentifierInfo *FI); +namespace { + class SubCheck { + SubChecker SC; + BugType **BT; + public: + SubCheck(SubChecker sc, BugType *& bt) : SC(sc), BT(&bt) {} + SubCheck() : SC(NULL), BT(NULL) {} + + void run(CheckerContext &C, const CallExpr *CE, + const IdentifierInfo *FI) const { + if (SC) + SC(C, CE, *BT, FI); + } + }; +} // end anonymous namespace + +void MacOSXAPIChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) { + // FIXME: Mostly copy and paste from UnixAPIChecker. Should refactor. + const GRState *state = C.getState(); + const Expr *Callee = CE->getCallee(); + const FunctionTextRegion *Fn = + dyn_cast_or_null<FunctionTextRegion>(state->getSVal(Callee).getAsRegion()); + + if (!Fn) + return; + + const IdentifierInfo *FI = Fn->getDecl()->getIdentifier(); + if (!FI) + return; + + const SubCheck &SC = + llvm::StringSwitch<SubCheck>(FI->getName()) + .Case("dispatch_once", SubCheck(CheckDispatchOnce, BTypes[DispatchOnce])) + .Case("dispatch_once_f", SubCheck(CheckDispatchOnce, + BTypes[DispatchOnceF])) + .Default(SubCheck()); + + SC.run(C, CE, FI); +} diff --git a/lib/Checker/MemRegion.cpp b/lib/Checker/MemRegion.cpp index 194015a..9a26988 100644 --- a/lib/Checker/MemRegion.cpp +++ b/lib/Checker/MemRegion.cpp @@ -419,20 +419,27 @@ const REG *MemRegionManager::LazyAllocate(REG*& region, ARG a) { const StackLocalsSpaceRegion* MemRegionManager::getStackLocalsRegion(const StackFrameContext *STC) { assert(STC); - if (STC == cachedStackLocalsFrame) - return cachedStackLocalsRegion; - cachedStackLocalsFrame = STC; - return LazyAllocate(cachedStackLocalsRegion, STC); + StackLocalsSpaceRegion *&R = StackLocalsSpaceRegions[STC]; + + if (R) + return R; + + R = A.Allocate<StackLocalsSpaceRegion>(); + new (R) StackLocalsSpaceRegion(this, STC); + return R; } const StackArgumentsSpaceRegion * MemRegionManager::getStackArgumentsRegion(const StackFrameContext *STC) { assert(STC); - if (STC == cachedStackArgumentsFrame) - return cachedStackArgumentsRegion; - - cachedStackArgumentsFrame = STC; - return LazyAllocate(cachedStackArgumentsRegion, STC); + StackArgumentsSpaceRegion *&R = StackArgumentsSpaceRegions[STC]; + + if (R) + return R; + + R = A.Allocate<StackArgumentsSpaceRegion>(); + new (R) StackArgumentsSpaceRegion(this, STC); + return R; } const GlobalsSpaceRegion *MemRegionManager::getGlobalsRegion() { diff --git a/lib/Checker/OSAtomicChecker.cpp b/lib/Checker/OSAtomicChecker.cpp index 7f4aeca..e743528 100644 --- a/lib/Checker/OSAtomicChecker.cpp +++ b/lib/Checker/OSAtomicChecker.cpp @@ -14,7 +14,6 @@ #include "GRExprEngineInternalChecks.h" #include "clang/Checker/PathSensitive/Checker.h" #include "clang/Basic/Builtins.h" -#include "llvm/ADT/StringSwitch.h" using namespace clang; diff --git a/lib/Checker/CheckObjCUnusedIVars.cpp b/lib/Checker/ObjCUnusedIVarsChecker.cpp index f2cf581..04d897a 100644 --- a/lib/Checker/CheckObjCUnusedIVars.cpp +++ b/lib/Checker/ObjCUnusedIVarsChecker.cpp @@ -1,4 +1,4 @@ -//==- CheckObjCUnusedIVars.cpp - Check for unused ivars ----------*- C++ -*-==// +//==- ObjCUnusedIVarsChecker.cpp - Check for unused ivars --------*- C++ -*-==// // // The LLVM Compiler Infrastructure // @@ -68,14 +68,14 @@ static void Scan(IvarUsageMap& M, const ObjCContainerDecl* D) { for (ObjCContainerDecl::instmeth_iterator I = D->instmeth_begin(), E = D->instmeth_end(); I!=E; ++I) Scan(M, (*I)->getBody()); - - if (const ObjCImplementationDecl *ID = dyn_cast<ObjCImplementationDecl>(D)) { + + if (const ObjCImplementationDecl *ID = dyn_cast<ObjCImplementationDecl>(D)) { // Scan for @synthesized property methods that act as setters/getters // to an ivar. for (ObjCImplementationDecl::propimpl_iterator I = ID->propimpl_begin(), E = ID->propimpl_end(); I!=E; ++I) Scan(M, *I); - + // Scan the associated categories as well. for (const ObjCCategoryDecl *CD = ID->getClassInterface()->getCategoryList(); CD ; @@ -92,7 +92,7 @@ static void Scan(IvarUsageMap &M, const DeclContext *C, const FileID FID, I!=E; ++I) if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) { SourceLocation L = FD->getLocStart(); - if (SM.getFileID(L) == FID) + if (SM.getFileID(L) == FID) Scan(M, FD->getBody()); } } @@ -109,12 +109,12 @@ void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D, const ObjCIvarDecl* ID = *I; - // Ignore ivars that aren't private. - if (ID->getAccessControl() != ObjCIvarDecl::Private) - continue; - - // Skip IB Outlets. - if (ID->getAttr<IBOutletAttr>()) + // Ignore ivars that... + // (a) aren't private + // (b) explicitly marked unused + // (c) are iboutlets + if (ID->getAccessControl() != ObjCIvarDecl::Private || + ID->getAttr<UnusedAttr>() || ID->getAttr<IBOutletAttr>()) continue; M[ID] = Unused; @@ -122,11 +122,10 @@ void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D, if (M.empty()) return; - + // Now scan the implementation declaration. Scan(M, D); - // Any potentially unused ivars? bool hasUnused = false; for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I) @@ -134,10 +133,10 @@ void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D, hasUnused = true; break; } - + if (!hasUnused) return; - + // We found some potentially unused ivars. Scan the entire translation unit // for functions inside the @implementation that reference these ivars. // FIXME: In the future hopefully we can just use the lexical DeclContext diff --git a/lib/Checker/RegionStore.cpp b/lib/Checker/RegionStore.cpp index f70105a..fd48f72 100644 --- a/lib/Checker/RegionStore.cpp +++ b/lib/Checker/RegionStore.cpp @@ -975,8 +975,10 @@ SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) { if (isa<AllocaRegion>(MR) || isa<SymbolicRegion>(MR)) MR = GetElementZeroRegion(MR, T); - if (isa<CodeTextRegion>(MR)) + if (isa<CodeTextRegion>(MR)) { + assert(0 && "Why load from a code text region?"); return UnknownVal(); + } // FIXME: Perhaps this method should just take a 'const MemRegion*' argument // instead of 'Loc', and have the other Loc cases handled at a higher level. @@ -1068,7 +1070,7 @@ SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) { } // All other values are symbolic. - return ValMgr.getRegionValueSymbolVal(R, RTy); + return ValMgr.getRegionValueSymbolVal(R); } std::pair<Store, const MemRegion *> @@ -1229,7 +1231,7 @@ SVal RegionStoreManager::RetrieveFieldOrElementCommon(Store store, } // All other values are symbolic. - return ValMgr.getRegionValueSymbolVal(R, Ty); + return ValMgr.getRegionValueSymbolVal(R); } SVal RegionStoreManager::RetrieveObjCIvar(Store store, const ObjCIvarRegion* R){ @@ -1269,11 +1271,11 @@ SVal RegionStoreManager::RetrieveVar(Store store, const VarRegion *R) { if (isa<UnknownSpaceRegion>(MS) || isa<StackArgumentsSpaceRegion>(MS)) - return ValMgr.getRegionValueSymbolVal(R, T); + return ValMgr.getRegionValueSymbolVal(R); if (isa<GlobalsSpaceRegion>(MS)) { if (VD->isFileVarDecl()) - return ValMgr.getRegionValueSymbolVal(R, T); + return ValMgr.getRegionValueSymbolVal(R); if (T->isIntegerType()) return ValMgr.makeIntVal(0, T); @@ -1291,7 +1293,7 @@ SVal RegionStoreManager::RetrieveLazySymbol(const TypedRegion *R) { QualType valTy = R->getValueType(getContext()); // All other values are symbolic. - return ValMgr.getRegionValueSymbolVal(R, valTy); + return ValMgr.getRegionValueSymbolVal(R); } SVal RegionStoreManager::RetrieveStruct(Store store, const TypedRegion* R) { diff --git a/lib/Checker/SymbolManager.cpp b/lib/Checker/SymbolManager.cpp index 40bdcf6..f2d630c 100644 --- a/lib/Checker/SymbolManager.cpp +++ b/lib/Checker/SymbolManager.cpp @@ -14,6 +14,7 @@ #include "clang/Checker/PathSensitive/SymbolManager.h" #include "clang/Checker/PathSensitive/MemRegion.h" +#include "clang/Analysis/AnalysisContext.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -78,14 +79,14 @@ void SymbolRegionValue::dumpToStream(llvm::raw_ostream& os) const { } const SymbolRegionValue* -SymbolManager::getRegionValueSymbol(const MemRegion* R, QualType T) { +SymbolManager::getRegionValueSymbol(const TypedRegion* R) { llvm::FoldingSetNodeID profile; - SymbolRegionValue::Profile(profile, R, T); + SymbolRegionValue::Profile(profile, R); void* InsertPos; SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); if (!SD) { SD = (SymExpr*) BPAlloc.Allocate<SymbolRegionValue>(); - new (SD) SymbolRegionValue(SymbolCounter, R, T); + new (SD) SymbolRegionValue(SymbolCounter, R); DataSet.InsertNode(SD, InsertPos); ++SymbolCounter; } @@ -175,13 +176,7 @@ QualType SymbolDerived::getType(ASTContext& Ctx) const { } QualType SymbolRegionValue::getType(ASTContext& C) const { - if (!T.isNull()) - return T; - - if (const TypedRegion* TR = dyn_cast<TypedRegion>(R)) - return TR->getValueType(C); - - return QualType(); + return R->getValueType(C); } SymbolManager::~SymbolManager() {} @@ -222,7 +217,11 @@ bool SymbolReaper::isLive(SymbolRef sym) { bool SymbolReaper::isLive(const Stmt *Loc, const VarRegion *VR) const { const StackFrameContext *SFC = VR->getStackFrame(); - return SFC == CurrentStackFrame ? Liveness.isLive(Loc, VR->getDecl()) : true; + + if (SFC == CurrentStackFrame) + return Liveness.isLive(Loc, VR->getDecl()); + else + return SFC->isParentOf(CurrentStackFrame); } SymbolVisitor::~SymbolVisitor() {} diff --git a/lib/Checker/UnixAPIChecker.cpp b/lib/Checker/UnixAPIChecker.cpp new file mode 100644 index 0000000..7ff817a --- /dev/null +++ b/lib/Checker/UnixAPIChecker.cpp @@ -0,0 +1,154 @@ +//= UnixAPIChecker.h - Checks preconditions for various Unix APIs --*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines UnixAPIChecker, which is an assortment of checks on calls +// to various, widely used UNIX/Posix functions. +// +//===----------------------------------------------------------------------===// + +#include "clang/Checker/PathSensitive/CheckerVisitor.h" +#include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/PathSensitive/GRStateTrait.h" +#include "llvm/ADT/StringSwitch.h" +#include "GRExprEngineInternalChecks.h" +#include <fcntl.h> + +using namespace clang; + +namespace { +class UnixAPIChecker : public CheckerVisitor<UnixAPIChecker> { + enum SubChecks { + OpenFn = 0, + NumChecks + }; + + BugType *BTypes[NumChecks]; + +public: + UnixAPIChecker() { memset(BTypes, 0, sizeof(*BTypes) * NumChecks); } + static void *getTag() { static unsigned tag = 0; return &tag; } + + void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE); +}; +} //end anonymous namespace + +void clang::RegisterUnixAPIChecker(GRExprEngine &Eng) { + Eng.registerCheck(new UnixAPIChecker()); +} + +//===----------------------------------------------------------------------===// +// Utility functions. +//===----------------------------------------------------------------------===// + +static inline void LazyInitialize(BugType *&BT, const char *name) { + if (BT) + return; + BT = new BugType(name, "Unix API"); +} + +//===----------------------------------------------------------------------===// +// "open" (man 2 open) +//===----------------------------------------------------------------------===// + +static void CheckOpen(CheckerContext &C, const CallExpr *CE, BugType *&BT) { + LazyInitialize(BT, "Improper use of 'open'"); + + // Look at the 'oflags' argument for the O_CREAT flag. + const GRState *state = C.getState(); + + if (CE->getNumArgs() < 2) { + // The frontend should issue a warning for this case, so this is a sanity + // check. + return; + } + + // Now check if oflags has O_CREAT set. + const Expr *oflagsEx = CE->getArg(1); + const SVal V = state->getSVal(oflagsEx); + if (!isa<NonLoc>(V)) { + // The case where 'V' can be a location can only be due to a bad header, + // so in this case bail out. + return; + } + NonLoc oflags = cast<NonLoc>(V); + NonLoc ocreateFlag = + cast<NonLoc>(C.getValueManager().makeIntVal((uint64_t) O_CREAT, + oflagsEx->getType())); + SVal maskedFlagsUC = C.getSValuator().EvalBinOpNN(state, BinaryOperator::And, + oflags, ocreateFlag, + oflagsEx->getType()); + if (maskedFlagsUC.isUnknownOrUndef()) + return; + DefinedSVal maskedFlags = cast<DefinedSVal>(maskedFlagsUC); + + // Check if maskedFlags is non-zero. + const GRState *trueState, *falseState; + llvm::tie(trueState, falseState) = state->Assume(maskedFlags); + + // Only emit an error if the value of 'maskedFlags' is properly + // constrained; + if (!(trueState && !falseState)) + return; + + if (CE->getNumArgs() < 3) { + ExplodedNode *N = C.GenerateSink(trueState); + if (!N) + return; + + EnhancedBugReport *report = + new EnhancedBugReport(*BT, + "Call to 'open' requires a third argument when " + "the 'O_CREAT' flag is set", N); + report->addRange(oflagsEx->getSourceRange()); + C.EmitReport(report); + } +} + +//===----------------------------------------------------------------------===// +// Central dispatch function. +//===----------------------------------------------------------------------===// + +typedef void (*SubChecker)(CheckerContext &C, const CallExpr *CE, BugType *&BT); +namespace { + class SubCheck { + SubChecker SC; + BugType **BT; + public: + SubCheck(SubChecker sc, BugType *& bt) : SC(sc), BT(&bt) {} + SubCheck() : SC(NULL), BT(NULL) {} + + void run(CheckerContext &C, const CallExpr *CE) const { + if (SC) + SC(C, CE, *BT); + } + }; +} // end anonymous namespace + +void UnixAPIChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) { + // Get the callee. All the functions we care about are C functions + // with simple identifiers. + const GRState *state = C.getState(); + const Expr *Callee = CE->getCallee(); + const FunctionTextRegion *Fn = + dyn_cast_or_null<FunctionTextRegion>(state->getSVal(Callee).getAsRegion()); + + if (!Fn) + return; + + const IdentifierInfo *FI = Fn->getDecl()->getIdentifier(); + if (!FI) + return; + + const SubCheck &SC = + llvm::StringSwitch<SubCheck>(FI->getName()) + .Case("open", SubCheck(CheckOpen, BTypes[OpenFn])) + .Default(SubCheck()); + + SC.run(C, CE); +} diff --git a/lib/Checker/ValueManager.cpp b/lib/Checker/ValueManager.cpp index 5359489..aa0c3c8 100644 --- a/lib/Checker/ValueManager.cpp +++ b/lib/Checker/ValueManager.cpp @@ -70,18 +70,14 @@ SVal ValueManager::convertToArrayIndex(SVal V) { return SVator->EvalCastNL(cast<NonLoc>(V), ArrayIndexTy); } -DefinedOrUnknownSVal ValueManager::getRegionValueSymbolVal(const MemRegion* R, - QualType T) { - - if (T.isNull()) { - const TypedRegion* TR = cast<TypedRegion>(R); - T = TR->getValueType(SymMgr.getContext()); - } +DefinedOrUnknownSVal +ValueManager::getRegionValueSymbolVal(const TypedRegion* R) { + QualType T = R->getValueType(SymMgr.getContext()); if (!SymbolManager::canSymbolicate(T)) return UnknownVal(); - SymbolRef sym = SymMgr.getRegionValueSymbol(R, T); + SymbolRef sym = SymMgr.getRegionValueSymbol(R); if (Loc::IsLocType(T)) return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym)); |