llvm::PointerIntPair<const ProgramPointTag *, 2, unsigned> Tag;
+ CFGBlock::ConstCFGElementRef ElemRef = {nullptr, 0};
+
protected:
ProgramPoint() = default;
- ProgramPoint(const void *P,
- Kind k,
- const LocationContext *l,
- const ProgramPointTag *tag = nullptr)
- : Data1(P),
- Data2(nullptr, (((unsigned) k) >> 0) & 0x3),
- L(l, (((unsigned) k) >> 2) & 0x3),
- Tag(tag, (((unsigned) k) >> 4) & 0x3) {
- assert(getKind() == k);
- assert(getLocationContext() == l);
- assert(getData1() == P);
- }
-
- ProgramPoint(const void *P1,
- const void *P2,
- Kind k,
- const LocationContext *l,
- const ProgramPointTag *tag = nullptr)
- : Data1(P1),
- Data2(P2, (((unsigned) k) >> 0) & 0x3),
- L(l, (((unsigned) k) >> 2) & 0x3),
- Tag(tag, (((unsigned) k) >> 4) & 0x3) {}
+ ProgramPoint(const void *P, Kind k, const LocationContext *l,
+ const ProgramPointTag *tag = nullptr,
+ CFGBlock::ConstCFGElementRef ElemRef = {nullptr, 0})
+ : Data1(P), Data2(nullptr, (((unsigned)k) >> 0) & 0x3),
+ L(l, (((unsigned)k) >> 2) & 0x3), Tag(tag, (((unsigned)k) >> 4) & 0x3),
+ ElemRef(ElemRef) {
+ assert(getKind() == k);
+ assert(getLocationContext() == l);
+ assert(getData1() == P);
+ }
+
+ ProgramPoint(const void *P1, const void *P2, Kind k, const LocationContext *l,
+ const ProgramPointTag *tag = nullptr,
+ CFGBlock::ConstCFGElementRef ElemRef = {nullptr, 0})
+ : Data1(P1), Data2(P2, (((unsigned)k) >> 0) & 0x3),
+ L(l, (((unsigned)k) >> 2) & 0x3), Tag(tag, (((unsigned)k) >> 4) & 0x3),
+ ElemRef(ElemRef) {}
protected:
const void *getData1() const { return Data1; }
const void *getData2() const { return Data2.getPointer(); }
void setData2(const void *d) { Data2.setPointer(d); }
+ CFGBlock::ConstCFGElementRef getElementRef() const { return ElemRef; }
public:
/// Create a new ProgramPoint object that is the same as the original
}
bool operator==(const ProgramPoint & RHS) const {
- return Data1 == RHS.Data1 &&
- Data2 == RHS.Data2 &&
- L == RHS.L &&
- Tag == RHS.Tag;
+ return Data1 == RHS.Data1 && Data2 == RHS.Data2 && L == RHS.L &&
+ Tag == RHS.Tag && ElemRef == RHS.ElemRef;
}
bool operator!=(const ProgramPoint &RHS) const {
- return Data1 != RHS.Data1 ||
- Data2 != RHS.Data2 ||
- L != RHS.L ||
- Tag != RHS.Tag;
+ return Data1 != RHS.Data1 || Data2 != RHS.Data2 || L != RHS.L ||
+ Tag != RHS.Tag || ElemRef != RHS.ElemRef;
}
void Profile(llvm::FoldingSetNodeID& ID) const {
ID.AddPointer(getData2());
ID.AddPointer(getLocationContext());
ID.AddPointer(getTag());
+ ID.AddPointer(ElemRef.getParent());
+ ID.AddInteger(ElemRef.getIndexInBlock());
}
void printJson(llvm::raw_ostream &Out, const char *NL = "\n") const;
}
};
+// FIXME: Eventually we want to take a CFGElementRef as parameter here too.
class StmtPoint : public ProgramPoint {
public:
StmtPoint(const Stmt *S, const void *p2, Kind k, const LocationContext *L,
class ImplicitCallPoint : public ProgramPoint {
public:
ImplicitCallPoint(const Decl *D, SourceLocation Loc, Kind K,
- const LocationContext *L, const ProgramPointTag *Tag)
- : ProgramPoint(Loc.getPtrEncoding(), D, K, L, Tag) {}
+ const LocationContext *L, const ProgramPointTag *Tag,
+ CFGBlock::ConstCFGElementRef ElemRef)
+ : ProgramPoint(Loc.getPtrEncoding(), D, K, L, Tag, ElemRef) {}
const Decl *getDecl() const { return static_cast<const Decl *>(getData2()); }
SourceLocation getLocation() const {
class PreImplicitCall : public ImplicitCallPoint {
public:
PreImplicitCall(const Decl *D, SourceLocation Loc, const LocationContext *L,
+ CFGBlock::ConstCFGElementRef ElemRef,
const ProgramPointTag *Tag = nullptr)
- : ImplicitCallPoint(D, Loc, PreImplicitCallKind, L, Tag) {}
+ : ImplicitCallPoint(D, Loc, PreImplicitCallKind, L, Tag, ElemRef) {}
private:
friend class ProgramPoint;
class PostImplicitCall : public ImplicitCallPoint {
public:
PostImplicitCall(const Decl *D, SourceLocation Loc, const LocationContext *L,
+ CFGBlock::ConstCFGElementRef ElemRef,
const ProgramPointTag *Tag = nullptr)
- : ImplicitCallPoint(D, Loc, PostImplicitCallKind, L, Tag) {}
+ : ImplicitCallPoint(D, Loc, PostImplicitCallKind, L, Tag, ElemRef) {}
private:
friend class ProgramPoint;
ProgramStateRef State;
const LocationContext *LCtx;
llvm::PointerUnion<const Expr *, const Decl *> Origin;
+ CFGBlock::ConstCFGElementRef ElemRef = {nullptr, 0};
mutable std::optional<bool> Foreign; // Set by CTU analysis.
protected:
protected:
friend class CallEventManager;
- CallEvent(const Expr *E, ProgramStateRef state, const LocationContext *lctx)
- : State(std::move(state)), LCtx(lctx), Origin(E) {}
+ CallEvent(const Expr *E, ProgramStateRef state, const LocationContext *lctx,
+ CFGBlock::ConstCFGElementRef ElemRef)
+ : State(std::move(state)), LCtx(lctx), Origin(E), ElemRef(ElemRef) {}
- CallEvent(const Decl *D, ProgramStateRef state, const LocationContext *lctx)
- : State(std::move(state)), LCtx(lctx), Origin(D) {}
+ CallEvent(const Decl *D, ProgramStateRef state, const LocationContext *lctx,
+ CFGBlock::ConstCFGElementRef ElemRef)
+ : State(std::move(state)), LCtx(lctx), Origin(D), ElemRef(ElemRef) {}
// DO NOT MAKE PUBLIC
CallEvent(const CallEvent &Original)
: State(Original.State), LCtx(Original.LCtx), Origin(Original.Origin),
- Data(Original.Data), Location(Original.Location) {}
+ ElemRef(Original.ElemRef), Data(Original.Data),
+ Location(Original.Location) {}
/// Copies this CallEvent, with vtable intact, into a new block of memory.
virtual void cloneTo(void *Dest) const = 0;
return LCtx;
}
+ const CFGBlock::ConstCFGElementRef &getCFGElementRef() const {
+ return ElemRef;
+ }
+
/// Returns the definition of the function or method that will be
/// called.
virtual RuntimeDefinition getRuntimeDefinition() const = 0;
class AnyFunctionCall : public CallEvent {
protected:
AnyFunctionCall(const Expr *E, ProgramStateRef St,
- const LocationContext *LCtx)
- : CallEvent(E, St, LCtx) {}
+ const LocationContext *LCtx,
+ CFGBlock::ConstCFGElementRef ElemRef)
+ : CallEvent(E, St, LCtx, ElemRef) {}
AnyFunctionCall(const Decl *D, ProgramStateRef St,
- const LocationContext *LCtx)
- : CallEvent(D, St, LCtx) {}
+ const LocationContext *LCtx,
+ CFGBlock::ConstCFGElementRef ElemRef)
+ : CallEvent(D, St, LCtx, ElemRef) {}
AnyFunctionCall(const AnyFunctionCall &Other) = default;
public:
protected:
SimpleFunctionCall(const CallExpr *CE, ProgramStateRef St,
- const LocationContext *LCtx)
- : AnyFunctionCall(CE, St, LCtx) {}
+ const LocationContext *LCtx,
+ CFGBlock::ConstCFGElementRef ElemRef)
+ : AnyFunctionCall(CE, St, LCtx, ElemRef) {}
SimpleFunctionCall(const SimpleFunctionCall &Other) = default;
void cloneTo(void *Dest) const override {
friend class CallEventManager;
protected:
- BlockCall(const CallExpr *CE, ProgramStateRef St,
- const LocationContext *LCtx)
- : CallEvent(CE, St, LCtx) {}
+ BlockCall(const CallExpr *CE, ProgramStateRef St, const LocationContext *LCtx,
+ CFGBlock::ConstCFGElementRef ElemRef)
+ : CallEvent(CE, St, LCtx, ElemRef) {}
BlockCall(const BlockCall &Other) = default;
void cloneTo(void *Dest) const override { new (Dest) BlockCall(*this); }
class CXXInstanceCall : public AnyFunctionCall {
protected:
CXXInstanceCall(const CallExpr *CE, ProgramStateRef St,
- const LocationContext *LCtx)
- : AnyFunctionCall(CE, St, LCtx) {}
+ const LocationContext *LCtx,
+ CFGBlock::ConstCFGElementRef ElemRef)
+ : AnyFunctionCall(CE, St, LCtx, ElemRef) {}
CXXInstanceCall(const FunctionDecl *D, ProgramStateRef St,
- const LocationContext *LCtx)
- : AnyFunctionCall(D, St, LCtx) {}
+ const LocationContext *LCtx,
+ CFGBlock::ConstCFGElementRef ElemRef)
+ : AnyFunctionCall(D, St, LCtx, ElemRef) {}
CXXInstanceCall(const CXXInstanceCall &Other) = default;
void getExtraInvalidatedValues(ValueList &Values,
protected:
CXXMemberCall(const CXXMemberCallExpr *CE, ProgramStateRef St,
- const LocationContext *LCtx)
- : CXXInstanceCall(CE, St, LCtx) {}
+ const LocationContext *LCtx,
+ CFGBlock::ConstCFGElementRef ElemRef)
+ : CXXInstanceCall(CE, St, LCtx, ElemRef) {}
CXXMemberCall(const CXXMemberCall &Other) = default;
void cloneTo(void *Dest) const override { new (Dest) CXXMemberCall(*this); }
protected:
CXXMemberOperatorCall(const CXXOperatorCallExpr *CE, ProgramStateRef St,
- const LocationContext *LCtx)
- : CXXInstanceCall(CE, St, LCtx) {}
+ const LocationContext *LCtx,
+ CFGBlock::ConstCFGElementRef ElemRef)
+ : CXXInstanceCall(CE, St, LCtx, ElemRef) {}
CXXMemberOperatorCall(const CXXMemberOperatorCall &Other) = default;
void cloneTo(void *Dest) const override {
/// \param Target The object region to be destructed.
/// \param St The path-sensitive state at this point in the program.
/// \param LCtx The location context at this point in the program.
+ /// \param ElemRef The reference to this destructor in the CFG.
+ ///
+ /// FIXME: Eventually we want to drop \param Target and deduce it from
+ /// \param ElemRef. To do that we need to migrate the logic for target
+ /// region lookup from ExprEngine::ProcessImplicitDtor() and make it
+ /// independent from ExprEngine.
CXXDestructorCall(const CXXDestructorDecl *DD, const Stmt *Trigger,
const MemRegion *Target, bool IsBaseDestructor,
- ProgramStateRef St, const LocationContext *LCtx)
- : CXXInstanceCall(DD, St, LCtx) {
+ ProgramStateRef St, const LocationContext *LCtx,
+ CFGBlock::ConstCFGElementRef ElemRef)
+ : CXXInstanceCall(DD, St, LCtx, ElemRef) {
Data = DtorDataTy(Target, IsBaseDestructor).getOpaqueValue();
Location = Trigger->getEndLoc();
}
class AnyCXXConstructorCall : public AnyFunctionCall {
protected:
AnyCXXConstructorCall(const Expr *E, const MemRegion *Target,
- ProgramStateRef St, const LocationContext *LCtx)
- : AnyFunctionCall(E, St, LCtx) {
+ ProgramStateRef St, const LocationContext *LCtx,
+ CFGBlock::ConstCFGElementRef ElemRef)
+ : AnyFunctionCall(E, St, LCtx, ElemRef) {
assert(E && (isa<CXXConstructExpr>(E) || isa<CXXInheritedCtorInitExpr>(E)));
// Target may be null when the region is unknown.
Data = Target;
/// 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.
+ /// \param ElemRef The reference to this constructor in the CFG.
+ ///
+ /// FIXME: Eventually we want to drop \param Target and deduce it from
+ /// \param ElemRef.
CXXConstructorCall(const CXXConstructExpr *CE, const MemRegion *Target,
- ProgramStateRef St, const LocationContext *LCtx)
- : AnyCXXConstructorCall(CE, Target, St, LCtx) {}
+ ProgramStateRef St, const LocationContext *LCtx,
+ CFGBlock::ConstCFGElementRef ElemRef)
+ : AnyCXXConstructorCall(CE, Target, St, LCtx, ElemRef) {}
CXXConstructorCall(const CXXConstructorCall &Other) = default;
protected:
CXXInheritedConstructorCall(const CXXInheritedCtorInitExpr *CE,
const MemRegion *Target, ProgramStateRef St,
- const LocationContext *LCtx)
- : AnyCXXConstructorCall(CE, Target, St, LCtx) {}
+ const LocationContext *LCtx,
+ CFGBlock::ConstCFGElementRef ElemRef)
+ : AnyCXXConstructorCall(CE, Target, St, LCtx, ElemRef) {}
CXXInheritedConstructorCall(const CXXInheritedConstructorCall &Other) =
default;
protected:
CXXAllocatorCall(const CXXNewExpr *E, ProgramStateRef St,
- const LocationContext *LCtx)
- : AnyFunctionCall(E, St, LCtx) {}
+ const LocationContext *LCtx,
+ CFGBlock::ConstCFGElementRef ElemRef)
+ : AnyFunctionCall(E, St, LCtx, ElemRef) {}
CXXAllocatorCall(const CXXAllocatorCall &Other) = default;
void cloneTo(void *Dest) const override { new (Dest) CXXAllocatorCall(*this); }
protected:
CXXDeallocatorCall(const CXXDeleteExpr *E, ProgramStateRef St,
- const LocationContext *LCtx)
- : AnyFunctionCall(E, St, LCtx) {}
+ const LocationContext *LCtx,
+ CFGBlock::ConstCFGElementRef ElemRef)
+ : AnyFunctionCall(E, St, LCtx, ElemRef) {}
CXXDeallocatorCall(const CXXDeallocatorCall &Other) = default;
void cloneTo(void *Dest) const override {
protected:
ObjCMethodCall(const ObjCMessageExpr *Msg, ProgramStateRef St,
- const LocationContext *LCtx)
- : CallEvent(Msg, St, LCtx) {
+ const LocationContext *LCtx,
+ CFGBlock::ConstCFGElementRef ElemRef)
+ : CallEvent(Msg, St, LCtx, ElemRef) {
Data = nullptr;
}
}
template <typename T, typename Arg>
- T *create(Arg A, ProgramStateRef St, const LocationContext *LCtx) {
+ T *create(Arg A, ProgramStateRef St, const LocationContext *LCtx,
+ CFGBlock::ConstCFGElementRef ElemRef) {
static_assert(sizeof(T) == sizeof(CallEventTemplateTy),
"CallEvent subclasses are not all the same size");
- return new (allocate()) T(A, St, LCtx);
+ return new (allocate()) T(A, St, LCtx, ElemRef);
}
template <typename T, typename Arg1, typename Arg2>
- T *create(Arg1 A1, Arg2 A2, ProgramStateRef St, const LocationContext *LCtx) {
+ T *create(Arg1 A1, Arg2 A2, ProgramStateRef St, const LocationContext *LCtx,
+ CFGBlock::ConstCFGElementRef ElemRef) {
static_assert(sizeof(T) == sizeof(CallEventTemplateTy),
"CallEvent subclasses are not all the same size");
- return new (allocate()) T(A1, A2, St, LCtx);
+ return new (allocate()) T(A1, A2, St, LCtx, ElemRef);
}
template <typename T, typename Arg1, typename Arg2, typename Arg3>
T *create(Arg1 A1, Arg2 A2, Arg3 A3, ProgramStateRef St,
- const LocationContext *LCtx) {
+ const LocationContext *LCtx, CFGBlock::ConstCFGElementRef ElemRef) {
static_assert(sizeof(T) == sizeof(CallEventTemplateTy),
"CallEvent subclasses are not all the same size");
- return new (allocate()) T(A1, A2, A3, St, LCtx);
+ return new (allocate()) T(A1, A2, A3, St, LCtx, ElemRef);
}
template <typename T, typename Arg1, typename Arg2, typename Arg3,
typename Arg4>
T *create(Arg1 A1, Arg2 A2, Arg3 A3, Arg4 A4, ProgramStateRef St,
- const LocationContext *LCtx) {
+ const LocationContext *LCtx, CFGBlock::ConstCFGElementRef ElemRef) {
static_assert(sizeof(T) == sizeof(CallEventTemplateTy),
"CallEvent subclasses are not all the same size");
- return new (allocate()) T(A1, A2, A3, A4, St, LCtx);
+ return new (allocate()) T(A1, A2, A3, A4, St, LCtx, ElemRef);
}
public:
/// Gets a call event for a function call, Objective-C method call,
/// a 'new', or a 'delete' call.
- CallEventRef<>
- getCall(const Stmt *S, ProgramStateRef State,
- const LocationContext *LC);
+ CallEventRef<> getCall(const Stmt *S, ProgramStateRef State,
+ const LocationContext *LC,
+ CFGBlock::ConstCFGElementRef ElemRef);
- CallEventRef<>
- getSimpleCall(const CallExpr *E, ProgramStateRef State,
- const LocationContext *LCtx);
+ CallEventRef<> getSimpleCall(const CallExpr *E, ProgramStateRef State,
+ const LocationContext *LCtx,
+ CFGBlock::ConstCFGElementRef ElemRef);
CallEventRef<ObjCMethodCall>
getObjCMethodCall(const ObjCMessageExpr *E, ProgramStateRef State,
- const LocationContext *LCtx) {
- return create<ObjCMethodCall>(E, State, LCtx);
+ const LocationContext *LCtx,
+ CFGBlock::ConstCFGElementRef ElemRef) {
+ return create<ObjCMethodCall>(E, State, LCtx, ElemRef);
}
CallEventRef<CXXConstructorCall>
getCXXConstructorCall(const CXXConstructExpr *E, const MemRegion *Target,
- ProgramStateRef State, const LocationContext *LCtx) {
- return create<CXXConstructorCall>(E, Target, State, LCtx);
+ ProgramStateRef State, const LocationContext *LCtx,
+ CFGBlock::ConstCFGElementRef ElemRef) {
+ return create<CXXConstructorCall>(E, Target, State, LCtx, ElemRef);
}
CallEventRef<CXXInheritedConstructorCall>
getCXXInheritedConstructorCall(const CXXInheritedCtorInitExpr *E,
const MemRegion *Target, ProgramStateRef State,
- const LocationContext *LCtx) {
- return create<CXXInheritedConstructorCall>(E, Target, State, LCtx);
+ const LocationContext *LCtx,
+ CFGBlock::ConstCFGElementRef ElemRef) {
+ return create<CXXInheritedConstructorCall>(E, Target, State, LCtx, ElemRef);
}
CallEventRef<CXXDestructorCall>
getCXXDestructorCall(const CXXDestructorDecl *DD, const Stmt *Trigger,
const MemRegion *Target, bool IsBase,
- ProgramStateRef State, const LocationContext *LCtx) {
- return create<CXXDestructorCall>(DD, Trigger, Target, IsBase, State, LCtx);
+ ProgramStateRef State, const LocationContext *LCtx,
+ CFGBlock::ConstCFGElementRef ElemRef) {
+ return create<CXXDestructorCall>(DD, Trigger, Target, IsBase, State, LCtx,
+ ElemRef);
}
CallEventRef<CXXAllocatorCall>
getCXXAllocatorCall(const CXXNewExpr *E, ProgramStateRef State,
- const LocationContext *LCtx) {
- return create<CXXAllocatorCall>(E, State, LCtx);
+ const LocationContext *LCtx,
+ CFGBlock::ConstCFGElementRef ElemRef) {
+ return create<CXXAllocatorCall>(E, State, LCtx, ElemRef);
}
CallEventRef<CXXDeallocatorCall>
getCXXDeallocatorCall(const CXXDeleteExpr *E, ProgramStateRef State,
- const LocationContext *LCtx) {
- return create<CXXDeallocatorCall>(E, State, LCtx);
+ const LocationContext *LCtx,
+ CFGBlock::ConstCFGElementRef ElemRef) {
+ return create<CXXDeallocatorCall>(E, State, LCtx, ElemRef);
}
};
return (*G.roots_begin())->getLocation().getLocationContext();
}
+ CFGBlock::ConstCFGElementRef getCFGElementRef() const {
+ const CFGBlock *blockPtr = currBldrCtx ? currBldrCtx->getBlock() : nullptr;
+ return {blockPtr, currStmtIdx};
+ }
+
void GenerateAutoTransition(ExplodedNode *N);
void enqueueEndOfPath(ExplodedNodeSet &S);
void GenerateCallExitNode(ExplodedNode *N);
OS << OpCallE->getDirectCallee()->getDeclName();
} else if (const auto *CallE = dyn_cast<CallExpr>(S)) {
auto &CEMgr = BRC.getStateManager().getCallEventManager();
- CallEventRef<> Call = CEMgr.getSimpleCall(CallE, state, CurrentLC);
+ CallEventRef<> Call =
+ CEMgr.getSimpleCall(CallE, state, CurrentLC, {nullptr, 0});
if (const auto *D = dyn_cast_or_null<NamedDecl>(Call->getDecl()))
OS << D->getDeclName();
else
os << "Operator 'new'";
} else {
assert(isa<ObjCMessageExpr>(S));
- CallEventRef<ObjCMethodCall> Call =
- Mgr.getObjCMethodCall(cast<ObjCMessageExpr>(S), CurrSt, LCtx);
+ CallEventRef<ObjCMethodCall> Call = Mgr.getObjCMethodCall(
+ cast<ObjCMessageExpr>(S), CurrSt, LCtx, {nullptr, 0});
switch (Call->getMessageKind()) {
case OCM_Message:
}
}
- std::optional<CallEventRef<>> CE = Mgr.getCall(S, CurrSt, LCtx);
+ std::optional<CallEventRef<>> CE = Mgr.getCall(S, CurrSt, LCtx, {nullptr, 0});
auto Idx = findArgIdxOfSymbol(CurrSt, LCtx, Sym, CE);
// If index is not found, we assume that the symbol was returned.
ProgramPoint CallEvent::getProgramPoint(bool IsPreVisit,
const ProgramPointTag *Tag) const {
+
if (const Expr *E = getOriginExpr()) {
if (IsPreVisit)
return PreStmt(E, getLocationContext(), Tag);
const Decl *D = getDecl();
assert(D && "Cannot get a program point without a statement or decl");
+ assert(ElemRef.getParent() &&
+ "Cannot get a program point without a CFGElementRef");
SourceLocation Loc = getSourceRange().getBegin();
if (IsPreVisit)
- return PreImplicitCall(D, Loc, getLocationContext(), Tag);
- return PostImplicitCall(D, Loc, getLocationContext(), Tag);
+ return PreImplicitCall(D, Loc, getLocationContext(), ElemRef, Tag);
+ return PostImplicitCall(D, Loc, getLocationContext(), ElemRef, Tag);
}
SVal CallEvent::getArgSVal(unsigned Index) const {
CallEventRef<>
CallEventManager::getSimpleCall(const CallExpr *CE, ProgramStateRef State,
- const LocationContext *LCtx) {
+ const LocationContext *LCtx,
+ CFGBlock::ConstCFGElementRef ElemRef) {
if (const auto *MCE = dyn_cast<CXXMemberCallExpr>(CE))
- return create<CXXMemberCall>(MCE, State, LCtx);
+ return create<CXXMemberCall>(MCE, State, LCtx, ElemRef);
if (const auto *OpCE = dyn_cast<CXXOperatorCallExpr>(CE)) {
const FunctionDecl *DirectCallee = OpCE->getDirectCallee();
if (const auto *MD = dyn_cast<CXXMethodDecl>(DirectCallee))
if (MD->isInstance())
- return create<CXXMemberOperatorCall>(OpCE, State, LCtx);
+ return create<CXXMemberOperatorCall>(OpCE, State, LCtx, ElemRef);
} else if (CE->getCallee()->getType()->isBlockPointerType()) {
- return create<BlockCall>(CE, State, LCtx);
+ return create<BlockCall>(CE, State, LCtx, ElemRef);
}
// Otherwise, it's a normal function call, static member function call, or
// something we can't reason about.
- return create<SimpleFunctionCall>(CE, State, LCtx);
+ return create<SimpleFunctionCall>(CE, State, LCtx, ElemRef);
}
CallEventRef<>
ProgramStateRef State) {
const LocationContext *ParentCtx = CalleeCtx->getParent();
const LocationContext *CallerCtx = ParentCtx->getStackFrame();
+ CFGBlock::ConstCFGElementRef ElemRef = {CalleeCtx->getCallSiteBlock(),
+ CalleeCtx->getIndex()};
assert(CallerCtx && "This should not be used for top-level stack frames");
const Stmt *CallSite = CalleeCtx->getCallSite();
if (CallSite) {
- if (CallEventRef<> Out = getCall(CallSite, State, CallerCtx))
+ if (CallEventRef<> Out = getCall(CallSite, State, CallerCtx, ElemRef))
return Out;
SValBuilder &SVB = State->getStateManager().getSValBuilder();
SVal ThisVal = State->getSVal(ThisPtr);
if (const auto *CE = dyn_cast<CXXConstructExpr>(CallSite))
- return getCXXConstructorCall(CE, ThisVal.getAsRegion(), State, CallerCtx);
+ return getCXXConstructorCall(CE, ThisVal.getAsRegion(), State, CallerCtx,
+ ElemRef);
else if (const auto *CIE = dyn_cast<CXXInheritedCtorInitExpr>(CallSite))
return getCXXInheritedConstructorCall(CIE, ThisVal.getAsRegion(), State,
- CallerCtx);
+ CallerCtx, ElemRef);
else {
// All other cases are handled by getCall.
llvm_unreachable("This is not an inlineable statement");
return getCXXDestructorCall(Dtor, Trigger, ThisVal.getAsRegion(),
E.getAs<CFGBaseDtor>().has_value(), State,
- CallerCtx);
+ CallerCtx, ElemRef);
}
CallEventRef<> CallEventManager::getCall(const Stmt *S, ProgramStateRef State,
- const LocationContext *LC) {
+ const LocationContext *LC,
+ CFGBlock::ConstCFGElementRef ElemRef) {
if (const auto *CE = dyn_cast<CallExpr>(S)) {
- return getSimpleCall(CE, State, LC);
+ return getSimpleCall(CE, State, LC, ElemRef);
} else if (const auto *NE = dyn_cast<CXXNewExpr>(S)) {
- return getCXXAllocatorCall(NE, State, LC);
+ return getCXXAllocatorCall(NE, State, LC, ElemRef);
} else if (const auto *DE = dyn_cast<CXXDeleteExpr>(S)) {
- return getCXXDeallocatorCall(DE, State, LC);
+ return getCXXDeallocatorCall(DE, State, LC, ElemRef);
} else if (const auto *ME = dyn_cast<ObjCMessageExpr>(S)) {
- return getObjCMethodCall(ME, State, LC);
+ return getObjCMethodCall(ME, State, LC, ElemRef);
} else {
return nullptr;
}
else {
NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
const LocationContext *LCtx = Pred->getLocationContext();
- PostImplicitCall PP(NE->getOperatorNew(), NE->getBeginLoc(), LCtx);
+ PostImplicitCall PP(NE->getOperatorNew(), NE->getBeginLoc(), LCtx,
+ getCFGElementRef());
Bldr.generateNode(PP, Pred->getState(), Pred);
}
Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
static SimpleProgramPointTag PT(
"ExprEngine", "Skipping automatic 0 length array destruction, "
"which shouldn't be in the CFG.");
- PostImplicitCall PP(DtorDecl, varDecl->getLocation(), LCtx, &PT);
+ PostImplicitCall PP(DtorDecl, varDecl->getLocation(), LCtx,
+ getCFGElementRef(), &PT);
NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
Bldr.generateSink(PP, Pred->getState(), Pred);
return;
static SimpleProgramPointTag PT("ExprEngine",
"Prepare for object destruction");
- PreImplicitCall PP(DtorDecl, varDecl->getLocation(), LCtx, &PT);
+ PreImplicitCall PP(DtorDecl, varDecl->getLocation(), LCtx, getCFGElementRef(),
+ &PT);
Pred = Bldr.generateNode(PP, state, Pred);
if (!Pred)
const CXXRecordDecl *RD = BTy->getAsCXXRecordDecl();
const CXXDestructorDecl *Dtor = RD->getDestructor();
- PostImplicitCall PP(Dtor, DE->getBeginLoc(), LCtx);
+ PostImplicitCall PP(Dtor, DE->getBeginLoc(), LCtx, getCFGElementRef());
NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
Bldr.generateNode(PP, Pred->getState(), Pred);
return;
static SimpleProgramPointTag PT(
"ExprEngine", "Skipping 0 length array delete destruction");
- PostImplicitCall PP(getDtorDecl(DTy), DE->getBeginLoc(), LCtx, &PT);
+ PostImplicitCall PP(getDtorDecl(DTy), DE->getBeginLoc(), LCtx,
+ getCFGElementRef(), &PT);
NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
Bldr.generateNode(PP, Pred->getState(), Pred);
return;
NodeBuilder Bldr(Pred, Dst, getBuilderContext());
static SimpleProgramPointTag PT("ExprEngine",
"Prepare for object destruction");
- PreImplicitCall PP(getDtorDecl(DTy), DE->getBeginLoc(), LCtx, &PT);
+ PreImplicitCall PP(getDtorDecl(DTy), DE->getBeginLoc(), LCtx,
+ getCFGElementRef(), &PT);
Pred = Bldr.generateNode(PP, State, Pred);
if (!Pred)
static SimpleProgramPointTag PT(
"ExprEngine", "Skipping member 0 length array destruction, which "
"shouldn't be in the CFG.");
- PostImplicitCall PP(DtorDecl, Member->getLocation(), LCtx, &PT);
+ PostImplicitCall PP(DtorDecl, Member->getLocation(), LCtx,
+ getCFGElementRef(), &PT);
NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
Bldr.generateSink(PP, Pred->getState(), Pred);
return;
static SimpleProgramPointTag PT("ExprEngine",
"Prepare for object destruction");
- PreImplicitCall PP(DtorDecl, Member->getLocation(), LCtx, &PT);
+ PreImplicitCall PP(DtorDecl, Member->getLocation(), LCtx, getCFGElementRef(),
+ &PT);
Pred = Bldr.generateNode(PP, State, Pred);
if (!Pred)
NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
PostImplicitCall PP(D.getDestructorDecl(getContext()),
D.getBindTemporaryExpr()->getBeginLoc(),
- Pred->getLocationContext());
+ Pred->getLocationContext(), getCFGElementRef());
Bldr.generateNode(PP, State, Pred);
return;
}
};
if (const auto *CE = dyn_cast<CallExpr>(E)) {
- CallEventRef<> Caller = CEMgr.getSimpleCall(CE, State, LCtx);
+ CallEventRef<> Caller =
+ CEMgr.getSimpleCall(CE, State, LCtx, getCFGElementRef());
if (std::optional<SVal> V = getArgLoc(Caller))
return *V;
else
} else if (const auto *CCE = dyn_cast<CXXConstructExpr>(E)) {
// Don't bother figuring out the target region for the future
// constructor because we won't need it.
- CallEventRef<> Caller =
- CEMgr.getCXXConstructorCall(CCE, /*Target=*/nullptr, State, LCtx);
+ CallEventRef<> Caller = CEMgr.getCXXConstructorCall(
+ CCE, /*Target=*/nullptr, State, LCtx, getCFGElementRef());
if (std::optional<SVal> V = getArgLoc(Caller))
return *V;
else
break;
} else if (const auto *ME = dyn_cast<ObjCMessageExpr>(E)) {
- CallEventRef<> Caller = CEMgr.getObjCMethodCall(ME, State, LCtx);
+ CallEventRef<> Caller =
+ CEMgr.getObjCMethodCall(ME, State, LCtx, getCFGElementRef());
if (std::optional<SVal> V = getArgLoc(Caller))
return *V;
else
CallEventManager &CEMgr = getStateManager().getCallEventManager();
CallEventRef<> Call =
CIE ? (CallEventRef<>)CEMgr.getCXXInheritedConstructorCall(
- CIE, TargetRegion, State, LCtx)
+ CIE, TargetRegion, State, LCtx, getCFGElementRef())
: (CallEventRef<>)CEMgr.getCXXConstructorCall(
- CE, TargetRegion, State, LCtx);
+ CE, TargetRegion, State, LCtx, getCFGElementRef());
ExplodedNodeSet DstPreVisit;
getCheckerManager().runCheckersForPreStmt(DstPreVisit, Pred, E, *this);
// it would interrupt the analysis instead.
static SimpleProgramPointTag T("ExprEngine", "SkipInvalidDestructor");
// FIXME: PostImplicitCall with a null decl may crash elsewhere anyway.
- PostImplicitCall PP(/*Decl=*/nullptr, S->getEndLoc(), LCtx, &T);
+ PostImplicitCall PP(/*Decl=*/nullptr, S->getEndLoc(), LCtx,
+ getCFGElementRef(), &T);
NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
Bldr.generateNode(PP, Pred->getState(), Pred);
return;
}
CallEventManager &CEMgr = getStateManager().getCallEventManager();
- CallEventRef<CXXDestructorCall> Call =
- CEMgr.getCXXDestructorCall(DtorDecl, S, Dest, IsBaseDtor, State, LCtx);
+ CallEventRef<CXXDestructorCall> Call = CEMgr.getCXXDestructorCall(
+ DtorDecl, S, Dest, IsBaseDtor, State, LCtx, getCFGElementRef());
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
Call->getSourceRange().getBegin(),
"Error evaluating New Allocator Call");
CallEventManager &CEMgr = getStateManager().getCallEventManager();
CallEventRef<CXXAllocatorCall> Call =
- CEMgr.getCXXAllocatorCall(CNE, State, LCtx);
+ CEMgr.getCXXAllocatorCall(CNE, State, LCtx, getCFGElementRef());
ExplodedNodeSet DstPreCall;
getCheckerManager().runCheckersForPreCall(DstPreCall, Pred,
CallEventManager &CEMgr = getStateManager().getCallEventManager();
CallEventRef<CXXAllocatorCall> Call =
- CEMgr.getCXXAllocatorCall(CNE, State, LCtx);
+ CEMgr.getCXXAllocatorCall(CNE, State, LCtx, getCFGElementRef());
if (!AMgr.getAnalyzerOptions().MayInlineCXXAllocator) {
// Invalidate placement args.
CallEventManager &CEMgr = getStateManager().getCallEventManager();
CallEventRef<CXXDeallocatorCall> Call = CEMgr.getCXXDeallocatorCall(
- CDE, Pred->getState(), Pred->getLocationContext());
+ CDE, Pred->getState(), Pred->getLocationContext(), getCFGElementRef());
ExplodedNodeSet DstPreCall;
getCheckerManager().runCheckersForPreCall(DstPreCall, Pred, *Call, *this);
// Get the call in its initial state. We use this as a template to perform
// all the checks.
CallEventManager &CEMgr = getStateManager().getCallEventManager();
- CallEventRef<> CallTemplate
- = CEMgr.getSimpleCall(CE, Pred->getState(), Pred->getLocationContext());
+ CallEventRef<> CallTemplate = CEMgr.getSimpleCall(
+ CE, Pred->getState(), Pred->getLocationContext(), getCFGElementRef());
// Evaluate the function call. We try each of the checkers
// to see if the can evaluate the function call.
State = bindReturnValue(Call, Pred->getLocationContext(), State);
// And make the result node.
- Bldr.generateNode(Call.getProgramPoint(), State, Pred);
+ static SimpleProgramPointTag PT("ExprEngine", "Conservative eval call");
+ Bldr.generateNode(Call.getProgramPoint(false, &PT), State, Pred);
}
ExprEngine::CallInlinePolicy
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
CallEventManager &CEMgr = getStateManager().getCallEventManager();
- CallEventRef<ObjCMethodCall> Msg =
- CEMgr.getObjCMethodCall(ME, Pred->getState(), Pred->getLocationContext());
+ CallEventRef<ObjCMethodCall> Msg = CEMgr.getObjCMethodCall(
+ ME, Pred->getState(), Pred->getLocationContext(), getCFGElementRef());
// There are three cases for the receiver:
// (1) it is definitely nil,
--- /dev/null
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.deadcode.UnreachableCode -verify %s
+// expected-no-diagnostics
+
+struct Test {
+ Test() {}
+ ~Test();
+};
+
+int foo() {
+ struct a {
+ Test b, c;
+ } d;
+ return 1;
+}
+
+int main() {
+ if (foo()) return 1; // <- this used to warn as unreachable
+}
--- /dev/null
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
+
+#include "Inputs/system-header-simulator-cxx.h"
+
+struct Test {
+ Test() {}
+ ~Test();
+};
+
+int foo() {
+ struct a {
+ // The dtor invocation of 'b' and 'c' used to create
+ // a loop in the egraph and the analysis stopped after
+ // this point.
+ Test b, c;
+ } d;
+ return 1;
+}
+
+int main() {
+ if (foo()) {
+ }
+
+ int x;
+ int y = x;
+ // expected-warning@-1{{Assigned value is garbage or undefined}}
+ (void)y;
+}
CallEventManager &CEMgr = Eng.getStateManager().getCallEventManager();
CallEventRef<> Call = [=, &CEMgr]() -> CallEventRef<CallEvent> {
+ CFGBlock::ConstCFGElementRef ElemRef = {SFC->getCallSiteBlock(),
+ SFC->getIndex()};
if (std::is_base_of<CallExpr, T>::value)
- return CEMgr.getCall(E, State, SFC);
+ return CEMgr.getCall(E, State, SFC, ElemRef);
if (std::is_same<T, CXXConstructExpr>::value)
return CEMgr.getCXXConstructorCall(cast<CXXConstructExpr>(E),
- /*Target=*/nullptr, State, SFC);
+ /*Target=*/nullptr, State, SFC,
+ ElemRef);
llvm_unreachable("Only these expressions are supported for now.");
}();