[cfe-commits] r160986 - in /cfe/trunk: include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp lib/StaticAnalyzer/Core/CallEvent.cpp lib/StaticAnalyzer/Core/CheckerManager.cpp lib/StaticAnalyzer/Core/ExprEngine.cpp lib/StaticAnalyzer/Core/ExprEngineCXX.cpp lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
Jordan Rose
jordan_rose at apple.com
Mon Jul 30 13:22:09 PDT 2012
Author: jrose
Date: Mon Jul 30 15:22:09 2012
New Revision: 160986
URL: http://llvm.org/viewvc/llvm-project?rev=160986&view=rev
Log:
[analyzer] Only allow CallEvents to be created by CallEventManager.
This ensures that it is valid to reference-count any CallEvents, and we
won't accidentally try to reclaim a CallEvent that lives on the stack.
It also hides an ugly switch statement for handling CallExprs!
There should be no functionality change here.
Modified:
cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp
cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp
cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h?rev=160986&r1=160985&r2=160986&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h Mon Jul 30 15:22:09 2012
@@ -48,8 +48,18 @@
};
class CallEvent;
-typedef IntrusiveRefCntPtr<CallEvent> CallEventRef;
+class CallEventManager;
+template<typename T = CallEvent>
+class CallEventRef : public IntrusiveRefCntPtr<const T> {
+public:
+ CallEventRef(const T *Call) : IntrusiveRefCntPtr<const T>(Call) {}
+ CallEventRef(const CallEventRef &Orig) : IntrusiveRefCntPtr<const T>(Orig) {}
+
+ CallEventRef<T> cloneWithState(ProgramStateRef State) const {
+ return this->getPtr()->template cloneWithState<T>(State);
+ }
+};
/// \brief Represents an abstract call to a function or method along a
/// particular path.
@@ -89,6 +99,8 @@
void Release() const;
protected:
+ friend class CallEventManager;
+
CallEvent(const Expr *E, ProgramStateRef state, const LocationContext *lctx)
: State(state), LCtx(lctx), Origin(E), RefCount(0) {}
@@ -100,6 +112,7 @@
: State(Original.State), LCtx(Original.LCtx), Origin(Original.Origin),
Data(Original.Data), Location(Original.Location), RefCount(0) {}
+
ProgramStateRef getState() const {
return State;
}
@@ -229,10 +242,10 @@
/// Returns a copy of this CallEvent, but using the given state.
template <typename T>
- IntrusiveRefCntPtr<T> cloneWithState(ProgramStateRef NewState) const;
+ CallEventRef<T> cloneWithState(ProgramStateRef NewState) const;
/// Returns a copy of this CallEvent, but using the given state.
- CallEventRef cloneWithState(ProgramStateRef NewState) const {
+ CallEventRef<> cloneWithState(ProgramStateRef NewState) const {
return cloneWithState<CallEvent>(NewState);
}
@@ -364,15 +377,17 @@
///
/// Example: \c fun()
class FunctionCall : public SimpleCall {
-protected:
- FunctionCall(const FunctionCall &Other) : SimpleCall(Other) {}
- virtual void cloneTo(void *Dest) const { new (Dest) FunctionCall(*this); }
+ friend class CallEventManager;
-public:
+protected:
FunctionCall(const CallExpr *CE, ProgramStateRef St,
const LocationContext *LCtx)
: SimpleCall(CE, St, LCtx) {}
+ FunctionCall(const FunctionCall &Other) : SimpleCall(Other) {}
+ virtual void cloneTo(void *Dest) const { new (Dest) FunctionCall(*this); }
+
+public:
virtual Kind getKind() const { return CE_Function; }
static bool classof(const CallEvent *CA) {
@@ -405,15 +420,17 @@
///
/// Example: \c obj.fun()
class CXXMemberCall : public CXXInstanceCall {
-protected:
- CXXMemberCall(const CXXMemberCall &Other) : CXXInstanceCall(Other) {}
- virtual void cloneTo(void *Dest) const { new (Dest) CXXMemberCall(*this); }
+ friend class CallEventManager;
-public:
+protected:
CXXMemberCall(const CXXMemberCallExpr *CE, ProgramStateRef St,
const LocationContext *LCtx)
: CXXInstanceCall(CE, St, LCtx) {}
+ CXXMemberCall(const CXXMemberCall &Other) : CXXInstanceCall(Other) {}
+ virtual void cloneTo(void *Dest) const { new (Dest) CXXMemberCall(*this); }
+
+public:
virtual const CXXMemberCallExpr *getOriginExpr() const {
return cast<CXXMemberCallExpr>(SimpleCall::getOriginExpr());
}
@@ -432,7 +449,13 @@
///
/// Example: <tt>iter + 1</tt>
class CXXMemberOperatorCall : public CXXInstanceCall {
+ friend class CallEventManager;
+
protected:
+ CXXMemberOperatorCall(const CXXOperatorCallExpr *CE, ProgramStateRef St,
+ const LocationContext *LCtx)
+ : CXXInstanceCall(CE, St, LCtx) {}
+
CXXMemberOperatorCall(const CXXMemberOperatorCall &Other)
: CXXInstanceCall(Other) {}
virtual void cloneTo(void *Dest) const {
@@ -440,10 +463,6 @@
}
public:
- CXXMemberOperatorCall(const CXXOperatorCallExpr *CE, ProgramStateRef St,
- const LocationContext *LCtx)
- : CXXInstanceCall(CE, St, LCtx) {}
-
virtual const CXXOperatorCallExpr *getOriginExpr() const {
return cast<CXXOperatorCallExpr>(SimpleCall::getOriginExpr());
}
@@ -468,7 +487,13 @@
///
/// Example: <tt>^{ /* ... */ }()</tt>
class BlockCall : public SimpleCall {
+ friend class CallEventManager;
+
protected:
+ BlockCall(const CallExpr *CE, ProgramStateRef St,
+ const LocationContext *LCtx)
+ : SimpleCall(CE, St, LCtx) {}
+
BlockCall(const BlockCall &Other) : SimpleCall(Other) {}
virtual void cloneTo(void *Dest) const { new (Dest) BlockCall(*this); }
@@ -477,10 +502,6 @@
virtual QualType getDeclaredResultType() const;
public:
- BlockCall(const CallExpr *CE, ProgramStateRef St,
- const LocationContext *LCtx)
- : SimpleCall(CE, St, LCtx) {}
-
/// \brief Returns the region associated with this instance of the block.
///
/// This may be NULL if the block's origin is unknown.
@@ -515,27 +536,28 @@
///
/// Example: \c T(1)
class CXXConstructorCall : public AnyFunctionCall {
-protected:
- CXXConstructorCall(const CXXConstructorCall &Other) : AnyFunctionCall(Other){}
- virtual void cloneTo(void *Dest) const { new (Dest) CXXConstructorCall(*this); }
-
- virtual void getExtraInvalidatedRegions(RegionList &Regions) const;
-
-public:
- /// Represents a constructor call to a new or unknown region.
- CXXConstructorCall(const CXXConstructExpr *CE, ProgramStateRef St,
- const LocationContext *LCtx)
- : AnyFunctionCall(CE, St, LCtx) {
- Data = 0;
- }
+ friend class CallEventManager;
- /// Represents a constructor call on an existing object region.
+protected:
+ /// Creates a constructor call.
+ ///
+ /// \param CE The constructor expression as written in the source.
+ /// \param Target The region where the object should be constructed. If NULL,
+ /// a new symbolic region will be used.
+ /// \param St The path-sensitive state at this point in the program.
+ /// \param LCtx The location context at this point in the program.
CXXConstructorCall(const CXXConstructExpr *CE, const MemRegion *target,
ProgramStateRef St, const LocationContext *LCtx)
: AnyFunctionCall(CE, St, LCtx) {
Data = target;
}
+ CXXConstructorCall(const CXXConstructorCall &Other) : AnyFunctionCall(Other){}
+ virtual void cloneTo(void *Dest) const { new (Dest) CXXConstructorCall(*this); }
+
+ virtual void getExtraInvalidatedRegions(RegionList &Regions) const;
+
+public:
virtual const CXXConstructExpr *getOriginExpr() const {
return cast<CXXConstructExpr>(AnyFunctionCall::getOriginExpr());
}
@@ -564,13 +586,9 @@
/// This can occur at the end of a scope (for automatic objects), at the end
/// of a full-expression (for temporaries), or as part of a delete.
class CXXDestructorCall : public AnyFunctionCall {
-protected:
- CXXDestructorCall(const CXXDestructorCall &Other) : AnyFunctionCall(Other) {}
- virtual void cloneTo(void *Dest) const { new (Dest) CXXDestructorCall(*this); }
-
- virtual void getExtraInvalidatedRegions(RegionList &Regions) const;
+ friend class CallEventManager;
-public:
+protected:
/// Creates an implicit destructor.
///
/// \param DD The destructor that will be called.
@@ -586,6 +604,12 @@
Location = Trigger->getLocEnd();
}
+ CXXDestructorCall(const CXXDestructorCall &Other) : AnyFunctionCall(Other) {}
+ virtual void cloneTo(void *Dest) const { new (Dest) CXXDestructorCall(*this); }
+
+ virtual void getExtraInvalidatedRegions(RegionList &Regions) const;
+
+public:
virtual SourceRange getSourceRange() const { return Location; }
virtual unsigned getNumArgs() const { return 0; }
@@ -603,15 +627,17 @@
///
/// This is a call to "operator new".
class CXXAllocatorCall : public AnyFunctionCall {
-protected:
- CXXAllocatorCall(const CXXAllocatorCall &Other) : AnyFunctionCall(Other) {}
- virtual void cloneTo(void *Dest) const { new (Dest) CXXAllocatorCall(*this); }
+ friend class CallEventManager;
-public:
+protected:
CXXAllocatorCall(const CXXNewExpr *E, ProgramStateRef St,
const LocationContext *LCtx)
: AnyFunctionCall(E, St, LCtx) {}
+ CXXAllocatorCall(const CXXAllocatorCall &Other) : AnyFunctionCall(Other) {}
+ virtual void cloneTo(void *Dest) const { new (Dest) CXXAllocatorCall(*this); }
+
+public:
virtual const CXXNewExpr *getOriginExpr() const {
return cast<CXXNewExpr>(AnyFunctionCall::getOriginExpr());
}
@@ -652,9 +678,17 @@
///
/// This includes all of the kinds listed in ObjCMessageKind.
class ObjCMethodCall : public CallEvent {
+ friend class CallEventManager;
+
const PseudoObjectExpr *getContainingPseudoObjectExpr() const;
protected:
+ ObjCMethodCall(const ObjCMessageExpr *Msg, ProgramStateRef St,
+ const LocationContext *LCtx)
+ : CallEvent(Msg, St, LCtx) {
+ Data = 0;
+ }
+
ObjCMethodCall(const ObjCMethodCall &Other) : CallEvent(Other) {}
virtual void cloneTo(void *Dest) const { new (Dest) ObjCMethodCall(*this); }
@@ -665,12 +699,6 @@
ObjCInterfaceDecl *ClassDecl) const;
public:
- ObjCMethodCall(const ObjCMessageExpr *Msg, ProgramStateRef St,
- const LocationContext *LCtx)
- : CallEvent(Msg, St, LCtx) {
- Data = 0;
- }
-
virtual const ObjCMessageExpr *getOriginExpr() const {
return cast<ObjCMessageExpr>(CallEvent::getOriginExpr());
}
@@ -763,7 +791,7 @@
friend class CallEvent;
llvm::BumpPtrAllocator &Alloc;
- SmallVector<void *, 4> Cache;
+ SmallVector<void *, 8> Cache;
void reclaim(const void *Memory) {
Cache.push_back(const_cast<void *>(Memory));
@@ -777,16 +805,64 @@
return Cache.pop_back_val();
}
+ template <typename T, typename Arg>
+ T *create(Arg A, ProgramStateRef St, const LocationContext *LCtx) {
+ return new (allocate()) T(A, St, LCtx);
+ }
+
+ template <typename T, typename Arg1, typename Arg2>
+ T *create(Arg1 A1, Arg2 A2, ProgramStateRef St, const LocationContext *LCtx) {
+ return new (allocate()) T(A1, A2, St, LCtx);
+ }
+
+ template <typename T, typename Arg1, typename Arg2, typename Arg3>
+ T *create(Arg1 A1, Arg2 A2, Arg3 A3, ProgramStateRef St,
+ const LocationContext *LCtx) {
+ return new (allocate()) T(A1, A2, A3, St, LCtx);
+ }
+
public:
CallEventManager(llvm::BumpPtrAllocator &alloc) : Alloc(alloc) {}
+
+ CallEventRef<SimpleCall>
+ getSimpleCall(const CallExpr *E, ProgramStateRef State,
+ const LocationContext *LCtx);
+
+ CallEventRef<ObjCMethodCall>
+ getObjCMethodCall(const ObjCMessageExpr *E, ProgramStateRef State,
+ const LocationContext *LCtx) {
+ return create<ObjCMethodCall>(E, State, LCtx);
+ }
+
+ CallEventRef<CXXConstructorCall>
+ getCXXConstructorCall(const CXXConstructExpr *E, const MemRegion *Target,
+ ProgramStateRef State, const LocationContext *LCtx) {
+ return create<CXXConstructorCall>(E, Target, State, LCtx);
+ }
+
+ CallEventRef<CXXDestructorCall>
+ getCXXDestructorCall(const CXXDestructorDecl *DD, const Stmt *Trigger,
+ const MemRegion *Target, ProgramStateRef State,
+ const LocationContext *LCtx) {
+ return create<CXXDestructorCall>(DD, Trigger, Target, State, LCtx);
+ }
+
+ CallEventRef<CXXAllocatorCall>
+ getCXXAllocatorCall(const CXXNewExpr *E, ProgramStateRef State,
+ const LocationContext *LCtx) {
+ return create<CXXAllocatorCall>(E, State, LCtx);
+ }
};
template <typename T>
-IntrusiveRefCntPtr<T> CallEvent::cloneWithState(ProgramStateRef NewState) const{
+CallEventRef<T> CallEvent::cloneWithState(ProgramStateRef NewState) const {
assert(isa<T>(*this) && "Cloning to unrelated type");
assert(sizeof(T) == sizeof(CallEvent) && "Subclasses may not add fields");
+ if (NewState == State)
+ return cast<T>(this);
+
CallEventManager &Mgr = State->getStateManager().getCallEventManager();
T *Copy = static_cast<T *>(Mgr.allocate());
cloneTo(Copy);
Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h?rev=160986&r1=160985&r2=160986&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h Mon Jul 30 15:22:09 2012
@@ -43,7 +43,6 @@
class AnalysisManager;
class CallEvent;
class SimpleCall;
-class ObjCMethodCall;
class ExprEngine : public SubEngine {
AnalysisManager &AMgr;
@@ -348,7 +347,7 @@
void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
ExplodedNode *Pred, ExplodedNodeSet &Dst);
- void VisitObjCMessage(const ObjCMethodCall &Msg, ExplodedNode *Pred,
+ void VisitObjCMessage(const ObjCMessageExpr *ME, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
/// VisitReturnStmt - Transfer function logic for return statements.
Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp?rev=160986&r1=160985&r2=160986&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp Mon Jul 30 15:22:09 2012
@@ -1975,8 +1975,11 @@
}
else {
assert(isa<ObjCMessageExpr>(S));
- ObjCMethodCall Call(cast<ObjCMessageExpr>(S), CurrSt, LCtx);
- switch (Call.getMessageKind()) {
+ CallEventManager &Mgr = CurrSt->getStateManager().getCallEventManager();
+ CallEventRef<ObjCMethodCall> Call
+ = Mgr.getObjCMethodCall(cast<ObjCMessageExpr>(S), CurrSt, LCtx);
+
+ switch (Call->getMessageKind()) {
case OCM_Message:
os << "Method";
break;
Modified: cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp?rev=160986&r1=160985&r2=160986&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp Mon Jul 30 15:22:09 2012
@@ -620,3 +620,24 @@
return Method;
}
+
+CallEventRef<SimpleCall>
+CallEventManager::getSimpleCall(const CallExpr *CE, ProgramStateRef State,
+ const LocationContext *LCtx) {
+ if (const CXXMemberCallExpr *MCE = dyn_cast<CXXMemberCallExpr>(CE))
+ return create<CXXMemberCall>(MCE, State, LCtx);
+
+ if (const CXXOperatorCallExpr *OpCE = dyn_cast<CXXOperatorCallExpr>(CE)) {
+ const FunctionDecl *DirectCallee = OpCE->getDirectCallee();
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DirectCallee))
+ if (MD->isInstance())
+ return create<CXXMemberOperatorCall>(OpCE, State, LCtx);
+
+ } else if (CE->getCallee()->getType()->isBlockPointerType()) {
+ return create<BlockCall>(CE, State, LCtx);
+ }
+
+ // Otherwise, it's a normal function call, static member function call, or
+ // something we can't reason about.
+ return create<FunctionCall>(CE, State, LCtx);
+}
Modified: cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp?rev=160986&r1=160985&r2=160986&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp Mon Jul 30 15:22:09 2012
@@ -192,15 +192,10 @@
void runChecker(CheckerManager::CheckObjCMessageFunc checkFn,
NodeBuilder &Bldr, ExplodedNode *Pred) {
- ProgramPoint::Kind K = IsPreVisit ? ProgramPoint::PreStmtKind :
- ProgramPoint::PostStmtKind;
- const ProgramPoint &L =
- ProgramPoint::getProgramPoint(Msg.getOriginExpr(),
- K, Pred->getLocationContext(),
- checkFn.Checker);
+ const ProgramPoint &L = Msg.getProgramPoint(IsPreVisit,checkFn.Checker);
CheckerContext C(Bldr, Eng, Pred, L);
- checkFn(Msg, C);
+ checkFn(*Msg.cloneWithState<ObjCMethodCall>(Pred->getState()), C);
}
};
}
@@ -237,10 +232,10 @@
void runChecker(CheckerManager::CheckCallFunc checkFn,
NodeBuilder &Bldr, ExplodedNode *Pred) {
- const ProgramPoint &L = Call.getProgramPoint(IsPreVisit, checkFn.Checker);
+ const ProgramPoint &L = Call.getProgramPoint(IsPreVisit,checkFn.Checker);
CheckerContext C(Bldr, Eng, Pred, L);
- checkFn(Call, C);
+ checkFn(*Call.cloneWithState(Pred->getState()), C);
}
};
}
Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=160986&r1=160985&r2=160986&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Mon Jul 30 15:22:09 2012
@@ -875,15 +875,11 @@
Bldr.addNodes(Dst);
break;
- case Stmt::ObjCMessageExprClass: {
+ case Stmt::ObjCMessageExprClass:
Bldr.takeNodes(Pred);
- ObjCMethodCall Call(cast<ObjCMessageExpr>(S),
- Pred->getState(),
- Pred->getLocationContext());
- VisitObjCMessage(Call, Pred, Dst);
+ VisitObjCMessage(cast<ObjCMessageExpr>(S), Pred, Dst);
Bldr.addNodes(Dst);
break;
- }
case Stmt::ObjCAtThrowStmtClass: {
// FIXME: This is not complete. We basically treat @throw as
Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp?rev=160986&r1=160985&r2=160986&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp Mon Jul 30 15:22:09 2012
@@ -125,23 +125,25 @@
}
}
- CXXConstructorCall Call(CE, Target, State, LCtx);
+ CallEventManager &CEMgr = getStateManager().getCallEventManager();
+ CallEventRef<CXXConstructorCall> Call =
+ CEMgr.getCXXConstructorCall(CE, Target, State, LCtx);
ExplodedNodeSet DstPreVisit;
getCheckerManager().runCheckersForPreStmt(DstPreVisit, Pred, CE, *this);
ExplodedNodeSet DstPreCall;
getCheckerManager().runCheckersForPreCall(DstPreCall, DstPreVisit,
- Call, *this);
+ *Call, *this);
ExplodedNodeSet DstInvalidated;
StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currentBuilderContext);
for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
I != E; ++I)
- defaultEvalCall(Bldr, *I, Call);
+ defaultEvalCall(Bldr, *I, *Call);
ExplodedNodeSet DstPostCall;
getCheckerManager().runCheckersForPostCall(DstPostCall, DstInvalidated,
- Call, *this);
+ *Call, *this);
getCheckerManager().runCheckersForPostStmt(destNodes, DstPostCall, CE, *this);
}
@@ -150,36 +152,39 @@
const Stmt *S,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
+ const LocationContext *LCtx = Pred->getLocationContext();
+ ProgramStateRef State = Pred->getState();
+
// FIXME: We need to run the same destructor on every element of the array.
// This workaround will just run the first destructor (which will still
// invalidate the entire array).
if (const ArrayType *AT = getContext().getAsArrayType(ObjectType)) {
ObjectType = AT->getElementType();
- Dest = Pred->getState()->getLValue(ObjectType,
- getSValBuilder().makeZeroArrayIndex(),
- loc::MemRegionVal(Dest)).getAsRegion();
+ Dest = State->getLValue(ObjectType, getSValBuilder().makeZeroArrayIndex(),
+ loc::MemRegionVal(Dest)).getAsRegion();
}
const CXXRecordDecl *RecordDecl = ObjectType->getAsCXXRecordDecl();
assert(RecordDecl && "Only CXXRecordDecls should have destructors");
const CXXDestructorDecl *DtorDecl = RecordDecl->getDestructor();
- CXXDestructorCall Call(DtorDecl, S, Dest, Pred->getState(),
- Pred->getLocationContext());
+ CallEventManager &CEMgr = getStateManager().getCallEventManager();
+ CallEventRef<CXXDestructorCall> Call =
+ CEMgr.getCXXDestructorCall(DtorDecl, S, Dest, State, LCtx);
ExplodedNodeSet DstPreCall;
getCheckerManager().runCheckersForPreCall(DstPreCall, Pred,
- Call, *this);
+ *Call, *this);
ExplodedNodeSet DstInvalidated;
StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currentBuilderContext);
for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
I != E; ++I)
- defaultEvalCall(Bldr, *I, Call);
+ defaultEvalCall(Bldr, *I, *Call);
ExplodedNodeSet DstPostCall;
getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated,
- Call, *this);
+ *Call, *this);
}
void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
@@ -196,9 +201,14 @@
svalBuilder.getConjuredSymbolVal(0, CNE, LCtx, CNE->getType(), blockCount);
ProgramStateRef State = Pred->getState();
+ CallEventManager &CEMgr = getStateManager().getCallEventManager();
+ CallEventRef<CXXAllocatorCall> Call =
+ CEMgr.getCXXAllocatorCall(CNE, State, LCtx);
+
// Invalidate placement args.
- CXXAllocatorCall Call(CNE, State, LCtx);
- State = Call.invalidateRegions(blockCount);
+ // FIXME: Once we figure out how we want allocators to work,
+ // we should be using the usual pre-/(default-)eval-/post-call checks here.
+ State = Call->invalidateRegions(blockCount);
if (CNE->isArray()) {
// FIXME: allocating an array requires simulating the constructors.
Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp?rev=160986&r1=160985&r2=160986&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp Mon Jul 30 15:22:09 2012
@@ -22,23 +22,6 @@
using namespace clang;
using namespace ento;
-static CallEventKind classifyCallExpr(const CallExpr *CE) {
- if (isa<CXXMemberCallExpr>(CE))
- return CE_CXXMember;
-
- const CXXOperatorCallExpr *OpCE = dyn_cast<CXXOperatorCallExpr>(CE);
- if (OpCE) {
- const FunctionDecl *DirectCallee = CE->getDirectCallee();
- if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DirectCallee))
- if (MD->isInstance())
- return CE_CXXMemberOperator;
- } else if (CE->getCallee()->getType()->isBlockPointerType()) {
- return CE_Block;
- }
-
- return CE_Function;
-}
-
void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) {
// Get the entry block in the CFG of the callee.
const StackFrameContext *calleeCtx = CE.getCalleeContext();
@@ -387,42 +370,18 @@
ExplodedNodeSet dstPreVisit;
getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, CE, *this);
- // Get the callee kind.
- CallEventKind K = classifyCallExpr(CE);
+ // Get the call in its initial state. We use this as a template to perform
+ // all the checks.
+ CallEventManager &CEMgr = getStateManager().getCallEventManager();
+ CallEventRef<SimpleCall> CallTemplate
+ = CEMgr.getSimpleCall(CE, Pred->getState(), Pred->getLocationContext());
// Evaluate the function call. We try each of the checkers
// to see if the can evaluate the function call.
ExplodedNodeSet dstCallEvaluated;
for (ExplodedNodeSet::iterator I = dstPreVisit.begin(), E = dstPreVisit.end();
I != E; ++I) {
- ProgramStateRef State = (*I)->getState();
- const LocationContext *LCtx = (*I)->getLocationContext();
-
- // Evaluate the call.
- switch (K) {
- case CE_Function: {
- FunctionCall Call(CE, State, LCtx);
- evalCall(dstCallEvaluated, *I, Call);
- break;
- }
- case CE_CXXMember: {
- CXXMemberCall Call(cast<CXXMemberCallExpr>(CE), State, LCtx);
- evalCall(dstCallEvaluated, *I, Call);
- break;
- }
- case CE_CXXMemberOperator: {
- CXXMemberOperatorCall Call(cast<CXXOperatorCallExpr>(CE), State, LCtx);
- evalCall(dstCallEvaluated, *I, Call);
- break;
- }
- case CE_Block: {
- BlockCall Call(CE, State, LCtx);
- evalCall(dstCallEvaluated, *I, Call);
- break;
- }
- default:
- llvm_unreachable("Non-CallExpr CallEventKind");
- }
+ evalCall(dstCallEvaluated, *I, *CallTemplate);
}
// Finally, perform the post-condition check of the CallExpr and store
@@ -435,6 +394,13 @@
void ExprEngine::evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
const SimpleCall &Call) {
+ // WARNING: At this time, the state attached to 'Call' may be older than the
+ // state in 'Pred'. This is a minor optimization since CheckerManager will
+ // use an updated CallEvent instance when calling checkers, but if 'Call' is
+ // ever used directly in this function all callers should be updated to pass
+ // the most recent state. (It is probably not worth doing the work here since
+ // for some callers this will not be necessary.)
+
// Run any pre-call checks using the generic call interface.
ExplodedNodeSet dstPreVisit;
getCheckerManager().runCheckersForPreCall(dstPreVisit, Pred, Call, *this);
@@ -483,36 +449,35 @@
}
void ExprEngine::defaultEvalCall(NodeBuilder &Bldr, ExplodedNode *Pred,
- const CallEvent &Call) {
- ProgramStateRef State = 0;
- const Expr *E = Call.getOriginExpr();
+ const CallEvent &CallTemplate) {
+ // Make sure we have the most recent state attached to the call.
+ ProgramStateRef State = Pred->getState();
+ CallEventRef<> Call = CallTemplate.cloneWithState(State);
// Try to inline the call.
// The origin expression here is just used as a kind of checksum;
- // for CallEvents that do not have origin expressions, this should still be
- // safe.
- State = getInlineFailedState(Pred->getState(), E);
- if (State == 0 && inlineCall(Call, Pred)) {
- // If we inlined the call, the successor has been manually added onto
- // the work list and we should not consider it for subsequent call
- // handling steps.
+ // this should still be safe even for CallEvents that don't come from exprs.
+ const Expr *E = Call->getOriginExpr();
+ ProgramStateRef InlinedFailedState = getInlineFailedState(State, E);
+
+ if (InlinedFailedState) {
+ // If we already tried once and failed, make sure we don't retry later.
+ State = InlinedFailedState;
+ } else if (inlineCall(*Call, Pred)) {
+ // If we decided to inline the call, the successor has been manually
+ // added onto the work list and we should not perform our generic
+ // call-handling steps.
Bldr.takeNodes(Pred);
return;
}
// If we can't inline it, handle the return value and invalidate the regions.
- if (State == 0)
- State = Pred->getState();
-
- // Invalidate any regions touched by the call.
unsigned Count = currentBuilderContext->getCurrentBlockCount();
- State = Call.invalidateRegions(Count, State);
-
- // Construct and bind the return value.
- State = bindReturnValue(Call, Pred->getLocationContext(), State);
+ State = Call->invalidateRegions(Count, State);
+ State = bindReturnValue(*Call, Pred->getLocationContext(), State);
// And make the result node.
- Bldr.generateNode(Call.getProgramPoint(), State, Pred);
+ Bldr.generateNode(Call->getProgramPoint(), State, Pred);
}
void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred,
Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp?rev=160986&r1=160985&r2=160986&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp Mon Jul 30 15:22:09 2012
@@ -140,17 +140,20 @@
return isSubclass(Class->getSuperClass(), II);
}
-void ExprEngine::VisitObjCMessage(const ObjCMethodCall &msg,
+void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
-
+ CallEventManager &CEMgr = getStateManager().getCallEventManager();
+ CallEventRef<ObjCMethodCall> Msg =
+ CEMgr.getObjCMethodCall(ME, Pred->getState(), Pred->getLocationContext());
+
// Handle the previsits checks.
ExplodedNodeSet dstPrevisit;
getCheckerManager().runCheckersForPreObjCMessage(dstPrevisit, Pred,
- msg, *this);
+ *Msg, *this);
ExplodedNodeSet dstGenericPrevisit;
getCheckerManager().runCheckersForPreCall(dstGenericPrevisit, dstPrevisit,
- msg, *this);
+ *Msg, *this);
// Proceed with evaluate the message expression.
ExplodedNodeSet dstEval;
@@ -159,16 +162,17 @@
for (ExplodedNodeSet::iterator DI = dstGenericPrevisit.begin(),
DE = dstGenericPrevisit.end(); DI != DE; ++DI) {
ExplodedNode *Pred = *DI;
+ ProgramStateRef State = Pred->getState();
+ CallEventRef<ObjCMethodCall> UpdatedMsg = Msg.cloneWithState(State);
- if (msg.isInstanceMessage()) {
- SVal recVal = msg.getReceiverSVal();
+ if (UpdatedMsg->isInstanceMessage()) {
+ SVal recVal = UpdatedMsg->getReceiverSVal();
if (!recVal.isUndef()) {
// Bifurcate the state into nil and non-nil ones.
DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal);
- ProgramStateRef state = Pred->getState();
ProgramStateRef notNilState, nilState;
- llvm::tie(notNilState, nilState) = state->assume(receiverVal);
+ llvm::tie(notNilState, nilState) = State->assume(receiverVal);
// There are three cases: can be nil or non-nil, must be nil, must be
// non-nil. We ignore must be nil, and merge the rest two into non-nil.
@@ -180,20 +184,20 @@
// Check if the "raise" message was sent.
assert(notNilState);
- if (msg.getSelector() == RaiseSel) {
+ if (Msg->getSelector() == RaiseSel) {
// If we raise an exception, for now treat it as a sink.
// Eventually we will want to handle exceptions properly.
- Bldr.generateNode(currentStmt, Pred, Pred->getState(), true);
+ Bldr.generateNode(currentStmt, Pred, State, true);
continue;
}
// Generate a transition to non-Nil state.
- if (notNilState != state)
+ if (notNilState != State)
Pred = Bldr.generateNode(currentStmt, Pred, notNilState);
}
} else {
// Check for special class methods.
- if (const ObjCInterfaceDecl *Iface = msg.getReceiverInterface()) {
+ if (const ObjCInterfaceDecl *Iface = Msg->getReceiverInterface()) {
if (!NSExceptionII) {
ASTContext &Ctx = getContext();
NSExceptionII = &Ctx.Idents.get("NSException");
@@ -222,7 +226,7 @@
Ctx.Selectors.getSelector(II.size(), &II[0]);
}
- Selector S = msg.getSelector();
+ Selector S = Msg->getSelector();
bool RaisesException = false;
for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i) {
if (S == NSExceptionInstanceRaiseSelectors[i]) {
@@ -240,16 +244,17 @@
}
}
}
- // Evaluate the call.
- defaultEvalCall(Bldr, Pred, msg);
+ // Evaluate the call.
+ defaultEvalCall(Bldr, Pred, *UpdatedMsg);
}
ExplodedNodeSet dstPostvisit;
- getCheckerManager().runCheckersForPostCall(dstPostvisit, dstEval, msg, *this);
+ getCheckerManager().runCheckersForPostCall(dstPostvisit, dstEval,
+ *Msg, *this);
// Finally, perform the post-condition check of the ObjCMessageExpr and store
// the created nodes in 'Dst'.
getCheckerManager().runCheckersForPostObjCMessage(Dst, dstPostvisit,
- msg, *this);
+ *Msg, *this);
}
More information about the cfe-commits
mailing list