[analyzer][NFC] Merge the class LocationContext into StackFrame (#198211)
This commit implements the final parts of the roadmap described in issue #190973 by merging the class `LocationContext` into the class `StackFrame` and replacing `LocationContext` with `StackFrame` throughout the analyzer.
This commit is contained in:
parent
ac2c011dd3
commit
35a10827d0
122 changed files with 2327 additions and 2652 deletions
|
|
@ -126,7 +126,7 @@ ExprEngine::inlineCall and ExprEngine::processCallExit.
|
|||
|
||||
If the conditions are right for inlining, a CallEnter node is created and added
|
||||
to the analysis work list. The CallEnter node marks the change to a new
|
||||
LocationContext representing the called function, and its state includes the
|
||||
StackFrame representing the called function, and its state includes the
|
||||
contents of the new stack frame. When the CallEnter node is actually processed,
|
||||
its single successor will be an edge to the first CFG block in the function.
|
||||
|
||||
|
|
@ -145,7 +145,7 @@ reasonable steps:
|
|||
bindings.
|
||||
|
||||
4. A CallExitEnd node is generated, which marks the transition back to the
|
||||
caller's LocationContext.
|
||||
caller's StackFrame.
|
||||
|
||||
5. Custom post-call checks are processed and the final nodes are pushed back
|
||||
onto the work list, so that evaluation of the caller can continue.
|
||||
|
|
@ -179,7 +179,7 @@ some cases, however, where the analyzer chooses not to inline:
|
|||
cannot be computed. These are prerequisites for analyzing a function body,
|
||||
with or without inlining.
|
||||
|
||||
- If the LocationContext chain for a given ExplodedNode reaches a maximum cutoff
|
||||
- If the StackFrame chain for a given ExplodedNode reaches a maximum cutoff
|
||||
depth. This prevents unbounded analysis due to infinite recursion, but also
|
||||
serves as a useful cutoff for performance reasons.
|
||||
|
||||
|
|
@ -377,7 +377,7 @@ CallEvent
|
|||
|
||||
A CallEvent represents a specific call to a function, method, or other body of
|
||||
code. It is path-sensitive, containing both the current state (ProgramStateRef)
|
||||
and stack space (LocationContext), and provides uniform access to the argument
|
||||
and stack space (StackFrame), and provides uniform access to the argument
|
||||
values and return type of a call, no matter how the call is written in the
|
||||
source or what sort of code body is being invoked.
|
||||
|
||||
|
|
|
|||
|
|
@ -38,8 +38,7 @@ class ASTContext;
|
|||
class BlockDecl;
|
||||
class CFGReverseBlockReachabilityAnalysis;
|
||||
class ImplicitParamDecl;
|
||||
class LocationContext;
|
||||
class LocationContextManager;
|
||||
class StackFrameManager;
|
||||
class ParentMap;
|
||||
class StackFrame;
|
||||
class Stmt;
|
||||
|
|
@ -176,11 +175,10 @@ public:
|
|||
/// AnalysisDeclContext wraps an ObjCMethodDecl or nullptr otherwise.
|
||||
const ImplicitParamDecl *getSelfDecl() const;
|
||||
|
||||
/// \copydoc LocationContextManager::getStackFrame()
|
||||
const StackFrame *getStackFrame(LocationContext const *ParentLC,
|
||||
const void *Data, const Expr *E,
|
||||
const CFGBlock *Blk, unsigned BlockCount,
|
||||
unsigned Index);
|
||||
/// \copydoc StackFrameManager::getStackFrame()
|
||||
const StackFrame *getStackFrame(const StackFrame *ParentSF, const void *Data,
|
||||
const Expr *E, const CFGBlock *Blk,
|
||||
unsigned BlockCount, unsigned Index);
|
||||
|
||||
/// \returns The specified analysis object, lazily running the analysis if
|
||||
/// necessary or nullptr if the analysis could not run.
|
||||
|
|
@ -200,96 +198,21 @@ public:
|
|||
private:
|
||||
std::unique_ptr<ManagedAnalysis> &getAnalysisImpl(const void *tag);
|
||||
|
||||
LocationContextManager &getLocationContextManager();
|
||||
StackFrameManager &getStackFrameManager();
|
||||
};
|
||||
|
||||
class LocationContext : public llvm::FoldingSetNode {
|
||||
public:
|
||||
enum ContextKind { StackFrameKind };
|
||||
|
||||
private:
|
||||
ContextKind Kind;
|
||||
/// It represents a stack frame of the call stack
|
||||
class StackFrame final : public llvm::FoldingSetNode {
|
||||
friend class StackFrameManager;
|
||||
|
||||
// AnalysisDeclContext can't be const since some methods may modify its
|
||||
// member.
|
||||
AnalysisDeclContext *Ctx;
|
||||
|
||||
const LocationContext *Parent;
|
||||
const StackFrame *Parent;
|
||||
|
||||
int64_t ID;
|
||||
|
||||
protected:
|
||||
LocationContext(ContextKind k, AnalysisDeclContext *ctx,
|
||||
const LocationContext *parent, int64_t ID)
|
||||
: Kind(k), Ctx(ctx), Parent(parent), ID(ID) {
|
||||
assert(ctx);
|
||||
}
|
||||
|
||||
public:
|
||||
virtual ~LocationContext();
|
||||
|
||||
ContextKind getKind() const { return Kind; }
|
||||
|
||||
int64_t getID() const { return ID; }
|
||||
|
||||
LLVM_ATTRIBUTE_RETURNS_NONNULL
|
||||
AnalysisDeclContext *getAnalysisDeclContext() const { return Ctx; }
|
||||
|
||||
/// It might return null.
|
||||
const LocationContext *getParent() const { return Parent; }
|
||||
|
||||
bool isParentOf(const LocationContext *LC) const;
|
||||
|
||||
const Decl *getDecl() const { return Ctx->getDecl(); }
|
||||
|
||||
CFG *getCFG() const { return Ctx->getCFG(); }
|
||||
|
||||
template <typename T> T *getAnalysis() const { return Ctx->getAnalysis<T>(); }
|
||||
|
||||
const ParentMap &getParentMap() const { return Ctx->getParentMap(); }
|
||||
|
||||
/// \copydoc AnalysisDeclContext::getSelfDecl()
|
||||
const ImplicitParamDecl *getSelfDecl() const { return Ctx->getSelfDecl(); }
|
||||
|
||||
const StackFrame *getStackFrame() const;
|
||||
|
||||
/// \returns Whether the current LocationContext has no caller context.
|
||||
virtual bool inTopFrame() const;
|
||||
|
||||
virtual void Profile(llvm::FoldingSetNodeID &ID) = 0;
|
||||
|
||||
/// Prints out the call stack.
|
||||
///
|
||||
/// \param Out The out stream.
|
||||
LLVM_DUMP_METHOD void dumpStack(raw_ostream &Out) const;
|
||||
|
||||
/// Prints out the call stack in \c json format.
|
||||
///
|
||||
/// \param Out The out stream.
|
||||
/// \param NL The newline.
|
||||
/// \param Space The space count for indentation.
|
||||
/// \param IsDot Whether the output format is \c dot.
|
||||
/// \param printMoreInfoPerContext
|
||||
/// A callback to print more information for each context, for example:
|
||||
/// \code
|
||||
/// [&](const LocationContext *LC) { LC->dump(); }
|
||||
/// \endcode
|
||||
void printJson(
|
||||
raw_ostream &Out, const char *NL = "\n", unsigned int Space = 0,
|
||||
bool IsDot = false,
|
||||
std::function<void(const LocationContext *)> printMoreInfoPerContext =
|
||||
[](const LocationContext *) {}) const;
|
||||
|
||||
LLVM_DUMP_METHOD void dump() const;
|
||||
|
||||
static void ProfileCommon(llvm::FoldingSetNodeID &ID, ContextKind ck,
|
||||
AnalysisDeclContext *ctx,
|
||||
const LocationContext *parent, const void *data);
|
||||
};
|
||||
|
||||
/// It represents a stack frame of the call stack (based on CallEvent).
|
||||
class StackFrame : public LocationContext {
|
||||
friend class LocationContextManager;
|
||||
|
||||
// Extra data for BlockInvocations
|
||||
const void *Data;
|
||||
|
||||
|
|
@ -307,14 +230,37 @@ class StackFrame : public LocationContext {
|
|||
// The index of the call site in the CFGBlock.
|
||||
const unsigned Index;
|
||||
|
||||
StackFrame(AnalysisDeclContext *ADC, const LocationContext *ParentLC,
|
||||
public:
|
||||
StackFrame(AnalysisDeclContext *ADC, const StackFrame *Parent,
|
||||
const void *Data, const Expr *E, const CFGBlock *Block,
|
||||
unsigned BlockCount, unsigned Index, int64_t ID)
|
||||
: LocationContext(StackFrameKind, ADC, ParentLC, ID), Data(Data),
|
||||
CallSite(E), Block(Block), BlockCount(BlockCount), Index(Index) {}
|
||||
: Ctx(ADC), Parent(Parent), ID(ID), Data(Data), CallSite(E), Block(Block),
|
||||
BlockCount(BlockCount), Index(Index) {
|
||||
assert(ADC);
|
||||
}
|
||||
|
||||
public:
|
||||
~StackFrame() override = default;
|
||||
~StackFrame() = default;
|
||||
|
||||
LLVM_ATTRIBUTE_RETURNS_NONNULL
|
||||
AnalysisDeclContext *getAnalysisDeclContext() const { return Ctx; }
|
||||
|
||||
/// It might return null.
|
||||
const StackFrame *getParent() const { return Parent; }
|
||||
|
||||
int64_t getID() const { return ID; }
|
||||
|
||||
bool isParentOf(const StackFrame *SF) const;
|
||||
|
||||
const Decl *getDecl() const { return Ctx->getDecl(); }
|
||||
|
||||
CFG *getCFG() const { return Ctx->getCFG(); }
|
||||
|
||||
template <typename T> T *getAnalysis() const { return Ctx->getAnalysis<T>(); }
|
||||
|
||||
const ParentMap &getParentMap() const { return Ctx->getParentMap(); }
|
||||
|
||||
/// \copydoc AnalysisDeclContext::getSelfDecl()
|
||||
const ImplicitParamDecl *getSelfDecl() const { return Ctx->getSelfDecl(); }
|
||||
|
||||
const void *getData() const { return Data; }
|
||||
|
||||
|
|
@ -322,43 +268,66 @@ public:
|
|||
|
||||
const CFGBlock *getCallSiteBlock() const { return Block; }
|
||||
|
||||
bool inTopFrame() const override { return getParent() == nullptr; }
|
||||
/// \returns Whether the current StackFrame has no caller context.
|
||||
bool inTopFrame() const { return getParent() == nullptr; }
|
||||
|
||||
unsigned getIndex() const { return Index; }
|
||||
|
||||
CFGElement getCallSiteCFGElement() const { return (*Block)[Index]; }
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) override;
|
||||
/// Prints out the call stack in \c json format.
|
||||
///
|
||||
/// \param Out The out stream.
|
||||
/// \param NL The newline.
|
||||
/// \param Space The space count for indentation.
|
||||
/// \param IsDot Whether the output format is \c dot.
|
||||
/// \param printMoreInfoPerStackFrame
|
||||
/// A callback to print more information for each stack frame, for example:
|
||||
/// \code
|
||||
/// [&](const StackFrame *SF) { SF->dump(); }
|
||||
/// \endcode
|
||||
void printJson(
|
||||
raw_ostream &Out, const char *NL = "\n", unsigned int Space = 0,
|
||||
bool IsDot = false,
|
||||
std::function<void(const StackFrame *)> printMoreInfoPerStackFrame =
|
||||
[](const StackFrame *) {}) const;
|
||||
|
||||
/// Prints out the call stack.
|
||||
///
|
||||
/// \param Out The out stream.
|
||||
LLVM_DUMP_METHOD void dumpStack(raw_ostream &Out) const;
|
||||
|
||||
LLVM_DUMP_METHOD void dump() const;
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID);
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ADC,
|
||||
const LocationContext *ParentLC, const void *Data,
|
||||
const Expr *E, const CFGBlock *Block, unsigned BlockCount,
|
||||
const StackFrame *SF, const void *Data, const Expr *E,
|
||||
const CFGBlock *Block, unsigned BlockCount,
|
||||
unsigned Index) {
|
||||
ProfileCommon(ID, StackFrameKind, ADC, ParentLC, E);
|
||||
ID.AddPointer(ADC);
|
||||
ID.AddPointer(SF);
|
||||
ID.AddPointer(E);
|
||||
ID.AddPointer(Data);
|
||||
ID.AddPointer(Block);
|
||||
ID.AddInteger(BlockCount);
|
||||
ID.AddInteger(Index);
|
||||
}
|
||||
|
||||
static bool classof(const LocationContext *LC) {
|
||||
return LC->getKind() == StackFrameKind;
|
||||
}
|
||||
};
|
||||
|
||||
class LocationContextManager {
|
||||
llvm::FoldingSet<LocationContext> Contexts;
|
||||
class StackFrameManager {
|
||||
llvm::FoldingSet<StackFrame> Frames;
|
||||
|
||||
// ID used for generating a new location context.
|
||||
// ID used for generating a new stack frame.
|
||||
int64_t NewID = 0;
|
||||
|
||||
public:
|
||||
~LocationContextManager();
|
||||
~StackFrameManager();
|
||||
|
||||
/// Obtain a context of the call stack using its parent context.
|
||||
///
|
||||
/// \param ADC The AnalysisDeclContext.
|
||||
/// \param ParentLC The parent context of this newly created
|
||||
/// \param ParentSF The parent context of this newly created
|
||||
/// context.
|
||||
/// \param Data Extra data in case this StackFrame is
|
||||
/// created for a BlockInvocation.
|
||||
|
|
@ -369,12 +338,11 @@ public:
|
|||
/// statements of the CFGBlock \p Block.
|
||||
/// \returns The stack frame context corresponding to the call.
|
||||
const StackFrame *getStackFrame(AnalysisDeclContext *ADC,
|
||||
const LocationContext *ParentLC,
|
||||
const void *Data, const Expr *E,
|
||||
const CFGBlock *Block, unsigned BlockCount,
|
||||
unsigned StmtIdx);
|
||||
const StackFrame *ParentSF, const void *Data,
|
||||
const Expr *E, const CFGBlock *Block,
|
||||
unsigned BlockCount, unsigned StmtIdx);
|
||||
|
||||
/// Discard all previously created LocationContext objects.
|
||||
/// Discard all previously created StackFrame objects.
|
||||
void clear();
|
||||
};
|
||||
|
||||
|
|
@ -383,7 +351,7 @@ class AnalysisDeclContextManager {
|
|||
llvm::DenseMap<const Decl *, std::unique_ptr<AnalysisDeclContext>>;
|
||||
|
||||
ContextMap Contexts;
|
||||
LocationContextManager LocCtxMgr;
|
||||
StackFrameManager SFMgr;
|
||||
CFG::BuildOptions cfgBuildOptions;
|
||||
|
||||
// Pointer to an interface that can provide function bodies for
|
||||
|
|
@ -423,9 +391,9 @@ public:
|
|||
/// Obtain the beginning context of the analysis.
|
||||
///
|
||||
/// \returns The top level stack frame for \p D.
|
||||
const StackFrame *getStackFrame(const Decl *D) {
|
||||
return LocCtxMgr.getStackFrame(getContext(D), nullptr, nullptr, nullptr,
|
||||
nullptr, 0, 0);
|
||||
const StackFrame *getTopStackFrame(const Decl *D) {
|
||||
return SFMgr.getStackFrame(getContext(D), nullptr, nullptr, nullptr,
|
||||
nullptr, 0, 0);
|
||||
}
|
||||
|
||||
BodyFarm &getBodyFarm();
|
||||
|
|
@ -436,7 +404,7 @@ public:
|
|||
private:
|
||||
friend class AnalysisDeclContext;
|
||||
|
||||
LocationContextManager &getLocationContextManager() { return LocCtxMgr; }
|
||||
StackFrameManager &getStackFrameManager() { return SFMgr; }
|
||||
};
|
||||
|
||||
} // namespace clang
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ class CallEnter;
|
|||
class CallExitEnd;
|
||||
class ConditionalOperator;
|
||||
class Decl;
|
||||
class LocationContext;
|
||||
class MemberExpr;
|
||||
class ProgramPoint;
|
||||
class SourceManager;
|
||||
|
|
@ -189,8 +188,8 @@ public:
|
|||
PathDiagnosticRange() = default;
|
||||
};
|
||||
|
||||
using LocationOrAnalysisDeclContext =
|
||||
llvm::PointerUnion<const LocationContext *, AnalysisDeclContext *>;
|
||||
using StackFrameOrAnalysisDeclContext =
|
||||
llvm::PointerUnion<const StackFrame *, AnalysisDeclContext *>;
|
||||
|
||||
class PathDiagnosticLocation {
|
||||
private:
|
||||
|
|
@ -205,12 +204,12 @@ private:
|
|||
PathDiagnosticLocation(SourceLocation L, const SourceManager &sm, Kind kind)
|
||||
: K(kind), SM(&sm), Loc(genLocation(L)), Range(genRange()) {}
|
||||
|
||||
FullSourceLoc genLocation(
|
||||
SourceLocation L = SourceLocation(),
|
||||
LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext *)nullptr) const;
|
||||
FullSourceLoc genLocation(SourceLocation L = SourceLocation(),
|
||||
StackFrameOrAnalysisDeclContext SFAC =
|
||||
(AnalysisDeclContext *)nullptr) const;
|
||||
|
||||
PathDiagnosticRange genRange(
|
||||
LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext *)nullptr) const;
|
||||
PathDiagnosticRange genRange(StackFrameOrAnalysisDeclContext SFAC =
|
||||
(AnalysisDeclContext *)nullptr) const;
|
||||
|
||||
public:
|
||||
/// Create an invalid location.
|
||||
|
|
@ -218,10 +217,10 @@ public:
|
|||
|
||||
/// Create a location corresponding to the given statement.
|
||||
PathDiagnosticLocation(const Stmt *s, const SourceManager &sm,
|
||||
LocationOrAnalysisDeclContext lac)
|
||||
StackFrameOrAnalysisDeclContext SFAC)
|
||||
: K(s->getBeginLoc().isValid() ? StmtK : SingleLocK),
|
||||
S(K == StmtK ? s : nullptr), SM(&sm),
|
||||
Loc(genLocation(SourceLocation(), lac)), Range(genRange(lac)) {
|
||||
Loc(genLocation(SourceLocation(), SFAC)), Range(genRange(SFAC)) {
|
||||
assert(K == SingleLocK || S);
|
||||
assert(K == SingleLocK || Loc.isValid());
|
||||
assert(K == SingleLocK || Range.isValid());
|
||||
|
|
@ -259,22 +258,22 @@ public:
|
|||
/// of statements and declarations.
|
||||
static PathDiagnosticLocation
|
||||
createBegin(const Decl *D, const SourceManager &SM,
|
||||
const LocationOrAnalysisDeclContext LAC) {
|
||||
const StackFrameOrAnalysisDeclContext SFAC) {
|
||||
return createBegin(D, SM);
|
||||
}
|
||||
|
||||
/// Create a location for the beginning of the statement.
|
||||
static PathDiagnosticLocation createBegin(const Stmt *S,
|
||||
const SourceManager &SM,
|
||||
const LocationOrAnalysisDeclContext LAC);
|
||||
static PathDiagnosticLocation
|
||||
createBegin(const Stmt *S, const SourceManager &SM,
|
||||
const StackFrameOrAnalysisDeclContext SFAC);
|
||||
|
||||
/// Create a location for the end of the statement.
|
||||
///
|
||||
/// If the statement is a CompoundStatement, the location will point to the
|
||||
/// closing brace instead of following it.
|
||||
static PathDiagnosticLocation createEnd(const Stmt *S,
|
||||
const SourceManager &SM,
|
||||
const LocationOrAnalysisDeclContext LAC);
|
||||
static PathDiagnosticLocation
|
||||
createEnd(const Stmt *S, const SourceManager &SM,
|
||||
const StackFrameOrAnalysisDeclContext SFAC);
|
||||
|
||||
/// Create the location for the operator of the binary expression.
|
||||
/// Assumes the statement has a valid location.
|
||||
|
|
@ -301,13 +300,13 @@ public:
|
|||
|
||||
/// Create a location for the beginning of the enclosing declaration body.
|
||||
/// Defaults to the beginning of the first statement in the declaration body.
|
||||
static PathDiagnosticLocation createDeclBegin(const LocationContext *LC,
|
||||
static PathDiagnosticLocation createDeclBegin(const StackFrame *SF,
|
||||
const SourceManager &SM);
|
||||
|
||||
/// Constructs a location for the end of the enclosing declaration body.
|
||||
/// Defaults to the end of brace.
|
||||
static PathDiagnosticLocation createDeclEnd(const LocationContext *LC,
|
||||
const SourceManager &SM);
|
||||
static PathDiagnosticLocation createDeclEnd(const StackFrame *SF,
|
||||
const SourceManager &SM);
|
||||
|
||||
/// Create a location corresponding to the given valid ProgramPoint.
|
||||
static PathDiagnosticLocation create(const ProgramPoint &P,
|
||||
|
|
@ -321,7 +320,7 @@ public:
|
|||
/// or the end of the given statement, or a nearby valid source location
|
||||
/// if the statement does not have a valid source location of its own.
|
||||
static SourceLocation
|
||||
getValidSourceLocation(const Stmt *S, LocationOrAnalysisDeclContext LAC,
|
||||
getValidSourceLocation(const Stmt *S, StackFrameOrAnalysisDeclContext SFAC,
|
||||
bool UseEndOfStatement = false);
|
||||
|
||||
bool operator==(const PathDiagnosticLocation &X) const {
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@
|
|||
namespace clang {
|
||||
|
||||
class AnalysisDeclContext;
|
||||
class LocationContext;
|
||||
|
||||
/// ProgramPoints can be "tagged" as representing points specific to a given
|
||||
/// analysis entity. Tags are abstract annotations, with an associated
|
||||
|
|
@ -95,9 +94,9 @@ private:
|
|||
const void *Data1;
|
||||
llvm::PointerIntPair<const void *, 2, unsigned> Data2;
|
||||
|
||||
// The LocationContext could be NULL to allow ProgramPoint to be used in
|
||||
// The StackFrame could be NULL to allow ProgramPoint to be used in
|
||||
// context insensitive analysis.
|
||||
llvm::PointerIntPair<const LocationContext *, 2, unsigned> L;
|
||||
llvm::PointerIntPair<const StackFrame *, 2, unsigned> S;
|
||||
|
||||
llvm::PointerIntPair<const ProgramPointTag *, 2, unsigned> Tag;
|
||||
|
||||
|
|
@ -105,22 +104,22 @@ private:
|
|||
|
||||
protected:
|
||||
ProgramPoint() = default;
|
||||
ProgramPoint(const void *P, Kind k, const LocationContext *l,
|
||||
ProgramPoint(const void *P, Kind k, const StackFrame *SF,
|
||||
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),
|
||||
S(SF, (((unsigned)k) >> 2) & 0x3), Tag(tag, (((unsigned)k) >> 4) & 0x3),
|
||||
ElemRef(ElemRef) {
|
||||
assert(getKind() == k);
|
||||
assert(getLocationContext() == l);
|
||||
assert(getStackFrame() == SF);
|
||||
assert(getData1() == P);
|
||||
}
|
||||
|
||||
ProgramPoint(const void *P1, const void *P2, Kind k, const LocationContext *l,
|
||||
ProgramPoint(const void *P1, const void *P2, Kind k, const StackFrame *SF,
|
||||
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),
|
||||
S(SF, (((unsigned)k) >> 2) & 0x3), Tag(tag, (((unsigned)k) >> 4) & 0x3),
|
||||
ElemRef(ElemRef) {}
|
||||
|
||||
protected:
|
||||
|
|
@ -133,8 +132,8 @@ public:
|
|||
/// Create a new ProgramPoint object that is the same as the original
|
||||
/// except for using the specified tag value.
|
||||
ProgramPoint withTag(const ProgramPointTag *tag) const {
|
||||
return ProgramPoint(getData1(), getData2(), getKind(),
|
||||
getLocationContext(), tag);
|
||||
return ProgramPoint(getData1(), getData2(), getKind(), getStackFrame(),
|
||||
tag);
|
||||
}
|
||||
|
||||
/// Convert to the specified ProgramPoint type, asserting that this
|
||||
|
|
@ -162,7 +161,7 @@ public:
|
|||
Kind getKind() const {
|
||||
unsigned x = Tag.getInt();
|
||||
x <<= 2;
|
||||
x |= L.getInt();
|
||||
x |= S.getInt();
|
||||
x <<= 2;
|
||||
x |= Data2.getInt();
|
||||
return (Kind) x;
|
||||
|
|
@ -178,13 +177,7 @@ public:
|
|||
|
||||
const ProgramPointTag *getTag() const { return Tag.getPointer(); }
|
||||
|
||||
const LocationContext *getLocationContext() const {
|
||||
return L.getPointer();
|
||||
}
|
||||
|
||||
const StackFrame *getStackFrame() const {
|
||||
return getLocationContext()->getStackFrame();
|
||||
}
|
||||
const StackFrame *getStackFrame() const { return S.getPointer(); }
|
||||
|
||||
// For use with DenseMap. This hash is probably slow.
|
||||
unsigned getHashValue() const {
|
||||
|
|
@ -194,12 +187,12 @@ public:
|
|||
}
|
||||
|
||||
bool operator==(const ProgramPoint & RHS) const {
|
||||
return Data1 == RHS.Data1 && Data2 == RHS.Data2 && L == RHS.L &&
|
||||
return Data1 == RHS.Data1 && Data2 == RHS.Data2 && S == RHS.S &&
|
||||
Tag == RHS.Tag && ElemRef == RHS.ElemRef;
|
||||
}
|
||||
|
||||
bool operator!=(const ProgramPoint &RHS) const {
|
||||
return Data1 != RHS.Data1 || Data2 != RHS.Data2 || L != RHS.L ||
|
||||
return Data1 != RHS.Data1 || Data2 != RHS.Data2 || S != RHS.S ||
|
||||
Tag != RHS.Tag || ElemRef != RHS.ElemRef;
|
||||
}
|
||||
|
||||
|
|
@ -207,7 +200,7 @@ public:
|
|||
ID.AddInteger((unsigned) getKind());
|
||||
ID.AddPointer(getData1());
|
||||
ID.AddPointer(getData2());
|
||||
ID.AddPointer(getLocationContext());
|
||||
ID.AddPointer(getStackFrame());
|
||||
ID.AddPointer(getTag());
|
||||
ID.AddPointer(ElemRef.getParent());
|
||||
ID.AddInteger(ElemRef.getIndexInBlock());
|
||||
|
|
@ -218,15 +211,15 @@ public:
|
|||
LLVM_DUMP_METHOD void dump() const;
|
||||
|
||||
static ProgramPoint getProgramPoint(const Stmt *S, ProgramPoint::Kind K,
|
||||
const LocationContext *LC,
|
||||
const StackFrame *SF,
|
||||
const ProgramPointTag *tag);
|
||||
};
|
||||
|
||||
class BlockEntrance : public ProgramPoint {
|
||||
public:
|
||||
BlockEntrance(const CFGBlock *PrevBlock, const CFGBlock *CurrBlock,
|
||||
const LocationContext *L, const ProgramPointTag *Tag = nullptr)
|
||||
: ProgramPoint(CurrBlock, PrevBlock, BlockEntranceKind, L, Tag) {
|
||||
const StackFrame *SF, const ProgramPointTag *Tag = nullptr)
|
||||
: ProgramPoint(CurrBlock, PrevBlock, BlockEntranceKind, SF, Tag) {
|
||||
assert(CurrBlock && "BlockEntrance requires non-null block");
|
||||
}
|
||||
|
||||
|
|
@ -253,8 +246,8 @@ private:
|
|||
|
||||
class BlockExit : public ProgramPoint {
|
||||
public:
|
||||
BlockExit(const CFGBlock *B, const LocationContext *L)
|
||||
: ProgramPoint(B, BlockExitKind, L) {}
|
||||
BlockExit(const CFGBlock *B, const StackFrame *SF)
|
||||
: ProgramPoint(B, BlockExitKind, SF) {}
|
||||
|
||||
const CFGBlock *getBlock() const {
|
||||
return reinterpret_cast<const CFGBlock*>(getData1());
|
||||
|
|
@ -275,9 +268,9 @@ private:
|
|||
// 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,
|
||||
StmtPoint(const Stmt *S, const void *p2, Kind k, const StackFrame *SF,
|
||||
const ProgramPointTag *tag)
|
||||
: ProgramPoint(S, p2, k, L, tag) {
|
||||
: ProgramPoint(S, p2, k, SF, tag) {
|
||||
assert(S);
|
||||
}
|
||||
|
||||
|
|
@ -299,9 +292,9 @@ private:
|
|||
|
||||
class PreStmt : public StmtPoint {
|
||||
public:
|
||||
PreStmt(const Stmt *S, const LocationContext *L, const ProgramPointTag *tag,
|
||||
PreStmt(const Stmt *S, const StackFrame *SF, const ProgramPointTag *tag,
|
||||
const Stmt *SubStmt = nullptr)
|
||||
: StmtPoint(S, SubStmt, PreStmtKind, L, tag) {}
|
||||
: StmtPoint(S, SubStmt, PreStmtKind, SF, tag) {}
|
||||
|
||||
const Stmt *getSubStmt() const { return (const Stmt*) getData2(); }
|
||||
|
||||
|
|
@ -316,18 +309,18 @@ private:
|
|||
class PostStmt : public StmtPoint {
|
||||
protected:
|
||||
PostStmt() = default;
|
||||
PostStmt(const Stmt *S, const void *data, Kind k, const LocationContext *L,
|
||||
PostStmt(const Stmt *S, const void *data, Kind k, const StackFrame *SF,
|
||||
const ProgramPointTag *tag = nullptr)
|
||||
: StmtPoint(S, data, k, L, tag) {}
|
||||
: StmtPoint(S, data, k, SF, tag) {}
|
||||
|
||||
public:
|
||||
explicit PostStmt(const Stmt *S, Kind k, const LocationContext *L,
|
||||
explicit PostStmt(const Stmt *S, Kind k, const StackFrame *SF,
|
||||
const ProgramPointTag *tag = nullptr)
|
||||
: StmtPoint(S, nullptr, k, L, tag) {}
|
||||
: StmtPoint(S, nullptr, k, SF, tag) {}
|
||||
|
||||
explicit PostStmt(const Stmt *S, const LocationContext *L,
|
||||
explicit PostStmt(const Stmt *S, const StackFrame *SF,
|
||||
const ProgramPointTag *tag = nullptr)
|
||||
: StmtPoint(S, nullptr, PostStmtKind, L, tag) {}
|
||||
: StmtPoint(S, nullptr, PostStmtKind, SF, tag) {}
|
||||
|
||||
private:
|
||||
friend class ProgramPoint;
|
||||
|
|
@ -339,13 +332,12 @@ private:
|
|||
|
||||
class FunctionExitPoint : public ProgramPoint {
|
||||
public:
|
||||
explicit FunctionExitPoint(const ReturnStmt *S,
|
||||
const LocationContext *LC,
|
||||
explicit FunctionExitPoint(const ReturnStmt *S, const StackFrame *SF,
|
||||
const ProgramPointTag *tag = nullptr)
|
||||
: ProgramPoint(S, FunctionExitKind, LC, tag) {}
|
||||
: ProgramPoint(S, FunctionExitKind, SF, tag) {}
|
||||
|
||||
const CFGBlock *getBlock() const {
|
||||
return &getLocationContext()->getCFG()->getExit();
|
||||
return &getStackFrame()->getCFG()->getExit();
|
||||
}
|
||||
|
||||
const ReturnStmt *getStmt() const {
|
||||
|
|
@ -363,9 +355,9 @@ private:
|
|||
// PostCondition represents the post program point of a branch condition.
|
||||
class PostCondition : public PostStmt {
|
||||
public:
|
||||
PostCondition(const Stmt *S, const LocationContext *L,
|
||||
PostCondition(const Stmt *S, const StackFrame *SF,
|
||||
const ProgramPointTag *tag = nullptr)
|
||||
: PostStmt(S, PostConditionKind, L, tag) {}
|
||||
: PostStmt(S, PostConditionKind, SF, tag) {}
|
||||
|
||||
private:
|
||||
friend class ProgramPoint;
|
||||
|
|
@ -378,9 +370,9 @@ private:
|
|||
class LocationCheck : public StmtPoint {
|
||||
protected:
|
||||
LocationCheck() = default;
|
||||
LocationCheck(const Stmt *S, const LocationContext *L,
|
||||
ProgramPoint::Kind K, const ProgramPointTag *tag)
|
||||
: StmtPoint(S, nullptr, K, L, tag) {}
|
||||
LocationCheck(const Stmt *S, const StackFrame *SF, ProgramPoint::Kind K,
|
||||
const ProgramPointTag *tag)
|
||||
: StmtPoint(S, nullptr, K, SF, tag) {}
|
||||
|
||||
private:
|
||||
friend class ProgramPoint;
|
||||
|
|
@ -392,9 +384,9 @@ private:
|
|||
|
||||
class PreLoad : public LocationCheck {
|
||||
public:
|
||||
PreLoad(const Stmt *S, const LocationContext *L,
|
||||
PreLoad(const Stmt *S, const StackFrame *SF,
|
||||
const ProgramPointTag *tag = nullptr)
|
||||
: LocationCheck(S, L, PreLoadKind, tag) {}
|
||||
: LocationCheck(S, SF, PreLoadKind, tag) {}
|
||||
|
||||
private:
|
||||
friend class ProgramPoint;
|
||||
|
|
@ -406,9 +398,9 @@ private:
|
|||
|
||||
class PreStore : public LocationCheck {
|
||||
public:
|
||||
PreStore(const Stmt *S, const LocationContext *L,
|
||||
PreStore(const Stmt *S, const StackFrame *SF,
|
||||
const ProgramPointTag *tag = nullptr)
|
||||
: LocationCheck(S, L, PreStoreKind, tag) {}
|
||||
: LocationCheck(S, SF, PreStoreKind, tag) {}
|
||||
|
||||
private:
|
||||
friend class ProgramPoint;
|
||||
|
|
@ -420,9 +412,9 @@ private:
|
|||
|
||||
class PostLoad : public PostStmt {
|
||||
public:
|
||||
PostLoad(const Stmt *S, const LocationContext *L,
|
||||
PostLoad(const Stmt *S, const StackFrame *SF,
|
||||
const ProgramPointTag *tag = nullptr)
|
||||
: PostStmt(S, PostLoadKind, L, tag) {}
|
||||
: PostStmt(S, PostLoadKind, SF, tag) {}
|
||||
|
||||
private:
|
||||
friend class ProgramPoint;
|
||||
|
|
@ -438,9 +430,9 @@ public:
|
|||
/// Construct the post store point.
|
||||
/// \param Loc can be used to store the information about the location
|
||||
/// used in the form it was uttered in the code.
|
||||
PostStore(const Stmt *S, const LocationContext *L, const void *Loc,
|
||||
PostStore(const Stmt *S, const StackFrame *SF, const void *Loc,
|
||||
const ProgramPointTag *tag = nullptr)
|
||||
: PostStmt(S, PostStoreKind, L, tag) {
|
||||
: PostStmt(S, PostStoreKind, SF, tag) {
|
||||
assert(getData2() == nullptr);
|
||||
setData2(Loc);
|
||||
}
|
||||
|
|
@ -461,9 +453,9 @@ private:
|
|||
|
||||
class PostLValue : public PostStmt {
|
||||
public:
|
||||
PostLValue(const Stmt *S, const LocationContext *L,
|
||||
PostLValue(const Stmt *S, const StackFrame *SF,
|
||||
const ProgramPointTag *tag = nullptr)
|
||||
: PostStmt(S, PostLValueKind, L, tag) {}
|
||||
: PostStmt(S, PostLValueKind, SF, tag) {}
|
||||
|
||||
private:
|
||||
friend class ProgramPoint;
|
||||
|
|
@ -477,9 +469,9 @@ private:
|
|||
/// processing the given statement.
|
||||
class PreStmtPurgeDeadSymbols : public StmtPoint {
|
||||
public:
|
||||
PreStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L,
|
||||
const ProgramPointTag *tag = nullptr)
|
||||
: StmtPoint(S, nullptr, PreStmtPurgeDeadSymbolsKind, L, tag) { }
|
||||
PreStmtPurgeDeadSymbols(const Stmt *S, const StackFrame *SF,
|
||||
const ProgramPointTag *tag = nullptr)
|
||||
: StmtPoint(S, nullptr, PreStmtPurgeDeadSymbolsKind, SF, tag) {}
|
||||
|
||||
private:
|
||||
friend class ProgramPoint;
|
||||
|
|
@ -493,9 +485,9 @@ private:
|
|||
/// processing the given statement.
|
||||
class PostStmtPurgeDeadSymbols : public StmtPoint {
|
||||
public:
|
||||
PostStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L,
|
||||
const ProgramPointTag *tag = nullptr)
|
||||
: StmtPoint(S, nullptr, PostStmtPurgeDeadSymbolsKind, L, tag) { }
|
||||
PostStmtPurgeDeadSymbols(const Stmt *S, const StackFrame *SF,
|
||||
const ProgramPointTag *tag = nullptr)
|
||||
: StmtPoint(S, nullptr, PostStmtPurgeDeadSymbolsKind, SF, tag) {}
|
||||
|
||||
private:
|
||||
friend class ProgramPoint;
|
||||
|
|
@ -507,8 +499,8 @@ private:
|
|||
|
||||
class BlockEdge : public ProgramPoint {
|
||||
public:
|
||||
BlockEdge(const CFGBlock *B1, const CFGBlock *B2, const LocationContext *L)
|
||||
: ProgramPoint(B1, B2, BlockEdgeKind, L) {
|
||||
BlockEdge(const CFGBlock *B1, const CFGBlock *B2, const StackFrame *SF)
|
||||
: ProgramPoint(B1, B2, BlockEdgeKind, SF) {
|
||||
assert(B1 && "BlockEdge: source block must be non-null");
|
||||
assert(B2 && "BlockEdge: destination block must be non-null");
|
||||
}
|
||||
|
|
@ -536,10 +528,9 @@ public:
|
|||
///
|
||||
/// \param I The initializer.
|
||||
/// \param Loc The location of the field being initialized.
|
||||
PostInitializer(const CXXCtorInitializer *I,
|
||||
const void *Loc,
|
||||
const LocationContext *L)
|
||||
: ProgramPoint(I, Loc, PostInitializerKind, L) {}
|
||||
PostInitializer(const CXXCtorInitializer *I, const void *Loc,
|
||||
const StackFrame *SF)
|
||||
: ProgramPoint(I, Loc, PostInitializerKind, SF) {}
|
||||
|
||||
const CXXCtorInitializer *getInitializer() const {
|
||||
return static_cast<const CXXCtorInitializer *>(getData1());
|
||||
|
|
@ -564,9 +555,9 @@ private:
|
|||
class ImplicitCallPoint : public ProgramPoint {
|
||||
public:
|
||||
ImplicitCallPoint(const Decl *D, SourceLocation Loc, Kind K,
|
||||
const LocationContext *L, const ProgramPointTag *Tag,
|
||||
const StackFrame *SF, const ProgramPointTag *Tag,
|
||||
CFGBlock::ConstCFGElementRef ElemRef)
|
||||
: ProgramPoint(Loc.getPtrEncoding(), D, K, L, Tag, ElemRef) {}
|
||||
: ProgramPoint(Loc.getPtrEncoding(), D, K, SF, Tag, ElemRef) {}
|
||||
|
||||
const Decl *getDecl() const { return static_cast<const Decl *>(getData2()); }
|
||||
SourceLocation getLocation() const {
|
||||
|
|
@ -588,10 +579,10 @@ private:
|
|||
/// Explicit calls will appear as PreStmt program points.
|
||||
class PreImplicitCall : public ImplicitCallPoint {
|
||||
public:
|
||||
PreImplicitCall(const Decl *D, SourceLocation Loc, const LocationContext *L,
|
||||
PreImplicitCall(const Decl *D, SourceLocation Loc, const StackFrame *SF,
|
||||
CFGBlock::ConstCFGElementRef ElemRef,
|
||||
const ProgramPointTag *Tag = nullptr)
|
||||
: ImplicitCallPoint(D, Loc, PreImplicitCallKind, L, Tag, ElemRef) {}
|
||||
: ImplicitCallPoint(D, Loc, PreImplicitCallKind, SF, Tag, ElemRef) {}
|
||||
|
||||
private:
|
||||
friend class ProgramPoint;
|
||||
|
|
@ -606,10 +597,10 @@ private:
|
|||
/// Explicit calls will appear as PostStmt program points.
|
||||
class PostImplicitCall : public ImplicitCallPoint {
|
||||
public:
|
||||
PostImplicitCall(const Decl *D, SourceLocation Loc, const LocationContext *L,
|
||||
PostImplicitCall(const Decl *D, SourceLocation Loc, const StackFrame *SF,
|
||||
CFGBlock::ConstCFGElementRef ElemRef,
|
||||
const ProgramPointTag *Tag = nullptr)
|
||||
: ImplicitCallPoint(D, Loc, PostImplicitCallKind, L, Tag, ElemRef) {}
|
||||
: ImplicitCallPoint(D, Loc, PostImplicitCallKind, SF, Tag, ElemRef) {}
|
||||
|
||||
private:
|
||||
friend class ProgramPoint;
|
||||
|
|
@ -621,9 +612,9 @@ private:
|
|||
|
||||
class PostAllocatorCall : public StmtPoint {
|
||||
public:
|
||||
PostAllocatorCall(const Stmt *S, const LocationContext *L,
|
||||
PostAllocatorCall(const Stmt *S, const StackFrame *SF,
|
||||
const ProgramPointTag *Tag = nullptr)
|
||||
: StmtPoint(S, nullptr, PostAllocatorCallKind, L, Tag) {}
|
||||
: StmtPoint(S, nullptr, PostAllocatorCallKind, SF, Tag) {}
|
||||
|
||||
private:
|
||||
friend class ProgramPoint;
|
||||
|
|
@ -634,24 +625,24 @@ private:
|
|||
};
|
||||
|
||||
/// Represents a point when we begin processing an inlined call.
|
||||
/// CallEnter uses the caller's location context.
|
||||
/// CallEnter uses the caller's stack frame.
|
||||
class CallEnter : public ProgramPoint {
|
||||
public:
|
||||
CallEnter(const Stmt *stmt, const StackFrame *CalleeSF,
|
||||
const LocationContext *callerCtx)
|
||||
: ProgramPoint(stmt, CalleeSF, CallEnterKind, callerCtx, nullptr) {}
|
||||
const StackFrame *CallerSF)
|
||||
: ProgramPoint(stmt, CalleeSF, CallEnterKind, CallerSF, nullptr) {}
|
||||
|
||||
const Stmt *getCallExpr() const {
|
||||
return static_cast<const Stmt *>(getData1());
|
||||
}
|
||||
|
||||
const StackFrame *getCalleeContext() const {
|
||||
const StackFrame *getCalleeStackFrame() const {
|
||||
return static_cast<const StackFrame *>(getData2());
|
||||
}
|
||||
|
||||
/// Returns the entry block in the CFG for the entered function.
|
||||
const CFGBlock *getEntry() const {
|
||||
const StackFrame *CalleeSF = getCalleeContext();
|
||||
const StackFrame *CalleeSF = getCalleeStackFrame();
|
||||
const CFG *CalleeCFG = CalleeSF->getCFG();
|
||||
return &(CalleeCFG->getEntry());
|
||||
}
|
||||
|
|
@ -675,7 +666,7 @@ private:
|
|||
/// - CallExitEnd
|
||||
class CallExitBegin : public ProgramPoint {
|
||||
public:
|
||||
// CallExitBegin uses the callee's location context.
|
||||
// CallExitBegin uses the callee's stack frame.
|
||||
CallExitBegin(const StackFrame *SF, const ReturnStmt *RS)
|
||||
: ProgramPoint(RS, CallExitBeginKind, SF, nullptr) {}
|
||||
|
||||
|
|
@ -695,11 +686,11 @@ private:
|
|||
/// \sa CallExitBegin
|
||||
class CallExitEnd : public ProgramPoint {
|
||||
public:
|
||||
// CallExitEnd uses the caller's location context.
|
||||
CallExitEnd(const StackFrame *CalleeSF, const LocationContext *CallerCtx)
|
||||
: ProgramPoint(CalleeSF, CallExitEndKind, CallerCtx, nullptr) {}
|
||||
// CallExitEnd uses the caller's stack frame.
|
||||
CallExitEnd(const StackFrame *CalleeSF, const StackFrame *CallerSF)
|
||||
: ProgramPoint(CalleeSF, CallExitEndKind, CallerSF, nullptr) {}
|
||||
|
||||
const StackFrame *getCalleeContext() const {
|
||||
const StackFrame *getCalleeStackFrame() const {
|
||||
return static_cast<const StackFrame *>(getData1());
|
||||
}
|
||||
|
||||
|
|
@ -719,12 +710,12 @@ private:
|
|||
/// result in a LoopExit program point.
|
||||
class LoopExit : public ProgramPoint {
|
||||
public:
|
||||
LoopExit(const Stmt *LoopStmt, const LocationContext *LC)
|
||||
: ProgramPoint(LoopStmt, nullptr, LoopExitKind, LC) {}
|
||||
LoopExit(const Stmt *LoopStmt, const StackFrame *SF)
|
||||
: ProgramPoint(LoopStmt, nullptr, LoopExitKind, SF) {}
|
||||
|
||||
const Stmt *getLoopStmt() const {
|
||||
return static_cast<const Stmt *>(getData1());
|
||||
}
|
||||
const Stmt *getLoopStmt() const {
|
||||
return static_cast<const Stmt *>(getData1());
|
||||
}
|
||||
|
||||
private:
|
||||
friend class ProgramPoint;
|
||||
|
|
@ -738,10 +729,10 @@ private:
|
|||
/// reasoning etc.
|
||||
class EpsilonPoint : public ProgramPoint {
|
||||
public:
|
||||
EpsilonPoint(const LocationContext *L, const void *Data1,
|
||||
EpsilonPoint(const StackFrame *SF, const void *Data1,
|
||||
const void *Data2 = nullptr,
|
||||
const ProgramPointTag *tag = nullptr)
|
||||
: ProgramPoint(Data1, Data2, EpsilonKind, L, tag) {}
|
||||
: ProgramPoint(Data1, Data2, EpsilonKind, SF, tag) {}
|
||||
|
||||
const void *getData() const { return getData1(); }
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ static constexpr TaintTagType TaintTagGeneric = 0;
|
|||
/// Create a new state in which the value of the expression is marked as
|
||||
/// tainted.
|
||||
[[nodiscard]] ProgramStateRef addTaint(ProgramStateRef State, const Expr *E,
|
||||
const LocationContext *LCtx,
|
||||
const StackFrame *SF,
|
||||
TaintTagType Kind = TaintTagGeneric);
|
||||
|
||||
/// Create a new state in which the value is marked as tainted.
|
||||
|
|
@ -63,8 +63,7 @@ addPartialTaint(ProgramStateRef State, SymbolRef ParentSym,
|
|||
TaintTagType Kind = TaintTagGeneric);
|
||||
|
||||
/// Check if the expression has a tainted value in the given state.
|
||||
bool isTainted(ProgramStateRef State, const Expr *E,
|
||||
const LocationContext *LCtx,
|
||||
bool isTainted(ProgramStateRef State, const Expr *E, const StackFrame *SF,
|
||||
TaintTagType Kind = TaintTagGeneric);
|
||||
|
||||
/// Check if the value is tainted in the given state.
|
||||
|
|
@ -82,7 +81,7 @@ bool isTainted(ProgramStateRef State, const MemRegion *Reg,
|
|||
|
||||
/// Returns the tainted Symbols for a given expression and state.
|
||||
std::vector<SymbolRef> getTaintedSymbols(ProgramStateRef State, const Expr *E,
|
||||
const LocationContext *LCtx,
|
||||
const StackFrame *SF,
|
||||
TaintTagType Kind = TaintTagGeneric);
|
||||
|
||||
/// Returns the tainted Symbols for a given SVal and state.
|
||||
|
|
@ -101,7 +100,7 @@ std::vector<SymbolRef> getTaintedSymbols(ProgramStateRef State,
|
|||
|
||||
std::vector<SymbolRef> getTaintedSymbolsImpl(ProgramStateRef State,
|
||||
const Expr *E,
|
||||
const LocationContext *LCtx,
|
||||
const StackFrame *SF,
|
||||
TaintTagType Kind,
|
||||
bool returnFirstOnly);
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@ namespace clang {
|
|||
class AnalyzerOptions;
|
||||
class ASTContext;
|
||||
class Decl;
|
||||
class LocationContext;
|
||||
class SourceManager;
|
||||
class Stmt;
|
||||
|
||||
|
|
@ -322,9 +321,9 @@ protected:
|
|||
llvm::DenseMap<const MemRegion *, bugreporter::TrackingKind>
|
||||
InterestingRegions;
|
||||
|
||||
/// A set of location contexts that correspoind to call sites which should be
|
||||
/// A set of stack frames that correspond to call sites which should be
|
||||
/// considered "interesting".
|
||||
llvm::SmallPtrSet<const LocationContext *, 2> InterestingLocationContexts;
|
||||
llvm::SmallPtrSet<const StackFrame *, 2> InterestingStackFrames;
|
||||
|
||||
/// A set of custom visitors which generate "event" diagnostics at
|
||||
/// interesting points in the path.
|
||||
|
|
@ -450,12 +449,12 @@ public:
|
|||
/// condition, will append "will be used as a condition" to the message).
|
||||
void markInteresting(SVal V, bugreporter::TrackingKind TKind =
|
||||
bugreporter::TrackingKind::Thorough);
|
||||
void markInteresting(const LocationContext *LC);
|
||||
void markInteresting(const StackFrame *SF);
|
||||
|
||||
bool isInteresting(SymbolRef sym) const;
|
||||
bool isInteresting(const MemRegion *R) const;
|
||||
bool isInteresting(SVal V) const;
|
||||
bool isInteresting(const LocationContext *LC) const;
|
||||
bool isInteresting(const StackFrame *SF) const;
|
||||
|
||||
std::optional<bugreporter::TrackingKind>
|
||||
getInterestingnessKind(SymbolRef sym) const;
|
||||
|
|
|
|||
|
|
@ -346,16 +346,13 @@ public:
|
|||
class RegionChanges {
|
||||
template <typename CHECKER>
|
||||
static ProgramStateRef
|
||||
_checkRegionChanges(void *checker,
|
||||
ProgramStateRef state,
|
||||
_checkRegionChanges(void *checker, ProgramStateRef state,
|
||||
const InvalidatedSymbols *invalidated,
|
||||
ArrayRef<const MemRegion *> Explicits,
|
||||
ArrayRef<const MemRegion *> Regions,
|
||||
const LocationContext *LCtx,
|
||||
ArrayRef<const MemRegion *> Regions, const StackFrame *SF,
|
||||
const CallEvent *Call) {
|
||||
return ((const CHECKER *) checker)->checkRegionChanges(state, invalidated,
|
||||
Explicits, Regions,
|
||||
LCtx, Call);
|
||||
return ((const CHECKER *)checker)
|
||||
->checkRegionChanges(state, invalidated, Explicits, Regions, SF, Call);
|
||||
}
|
||||
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ namespace clang {
|
|||
class AnalyzerOptions;
|
||||
class CallExpr;
|
||||
class Decl;
|
||||
class LocationContext;
|
||||
class Stmt;
|
||||
class TranslationUnitDecl;
|
||||
|
||||
|
|
@ -411,8 +410,7 @@ public:
|
|||
const InvalidatedSymbols *invalidated,
|
||||
ArrayRef<const MemRegion *> ExplicitRegions,
|
||||
ArrayRef<const MemRegion *> Regions,
|
||||
const LocationContext *LCtx,
|
||||
const CallEvent *Call);
|
||||
const StackFrame *SF, const CallEvent *Call);
|
||||
|
||||
/// Run checkers when pointers escape.
|
||||
///
|
||||
|
|
@ -523,13 +521,11 @@ public:
|
|||
|
||||
using CheckLiveSymbolsFunc = CheckerFn<void (ProgramStateRef,SymbolReaper &)>;
|
||||
|
||||
using CheckRegionChangesFunc =
|
||||
CheckerFn<ProgramStateRef (ProgramStateRef,
|
||||
const InvalidatedSymbols *symbols,
|
||||
ArrayRef<const MemRegion *> ExplicitRegions,
|
||||
ArrayRef<const MemRegion *> Regions,
|
||||
const LocationContext *LCtx,
|
||||
const CallEvent *Call)>;
|
||||
using CheckRegionChangesFunc = CheckerFn<ProgramStateRef(
|
||||
ProgramStateRef, const InvalidatedSymbols *symbols,
|
||||
ArrayRef<const MemRegion *> ExplicitRegions,
|
||||
ArrayRef<const MemRegion *> Regions, const StackFrame *SF,
|
||||
const CallEvent *Call)>;
|
||||
|
||||
using CheckPointerEscapeFunc =
|
||||
CheckerFn<ProgramStateRef (ProgramStateRef,
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@
|
|||
|
||||
namespace clang {
|
||||
|
||||
class LocationContext;
|
||||
class ProgramPoint;
|
||||
class ProgramPointTag;
|
||||
class StackFrame;
|
||||
|
|
@ -156,7 +155,7 @@ public:
|
|||
|
||||
private:
|
||||
ProgramStateRef State;
|
||||
const LocationContext *LCtx;
|
||||
const StackFrame *SF;
|
||||
llvm::PointerUnion<const Expr *, const Decl *> Origin;
|
||||
CFGBlock::ConstCFGElementRef ElemRef = {nullptr, 0};
|
||||
mutable std::optional<bool> Foreign; // Set by CTU analysis.
|
||||
|
|
@ -181,17 +180,17 @@ private:
|
|||
protected:
|
||||
friend class CallEventManager;
|
||||
|
||||
CallEvent(const Expr *E, ProgramStateRef state, const LocationContext *lctx,
|
||||
CallEvent(const Expr *E, ProgramStateRef state, const StackFrame *SF,
|
||||
CFGBlock::ConstCFGElementRef ElemRef)
|
||||
: State(std::move(state)), LCtx(lctx), Origin(E), ElemRef(ElemRef) {}
|
||||
: State(std::move(state)), SF(SF), Origin(E), ElemRef(ElemRef) {}
|
||||
|
||||
CallEvent(const Decl *D, ProgramStateRef state, const LocationContext *lctx,
|
||||
CallEvent(const Decl *D, ProgramStateRef state, const StackFrame *SF,
|
||||
CFGBlock::ConstCFGElementRef ElemRef)
|
||||
: State(std::move(state)), LCtx(lctx), Origin(D), ElemRef(ElemRef) {}
|
||||
: State(std::move(state)), SF(SF), Origin(D), ElemRef(ElemRef) {}
|
||||
|
||||
// DO NOT MAKE PUBLIC
|
||||
CallEvent(const CallEvent &Original)
|
||||
: State(Original.State), LCtx(Original.LCtx), Origin(Original.Origin),
|
||||
: State(Original.State), SF(Original.SF), Origin(Original.Origin),
|
||||
ElemRef(Original.ElemRef), Data(Original.Data),
|
||||
Location(Original.Location) {}
|
||||
|
||||
|
|
@ -200,7 +199,7 @@ protected:
|
|||
|
||||
/// Get the value of arbitrary expressions at this point in the path.
|
||||
SVal getSVal(const Expr *E) const {
|
||||
return getState()->getSVal(E, getLocationContext());
|
||||
return getState()->getSVal(E, getStackFrame());
|
||||
}
|
||||
|
||||
using ValueList = SmallVectorImpl<SVal>;
|
||||
|
|
@ -247,8 +246,8 @@ public:
|
|||
return getState()->getStateManager().getContext();
|
||||
}
|
||||
|
||||
/// The context in which the call is being evaluated.
|
||||
const LocationContext *getLocationContext() const { return LCtx; }
|
||||
/// The stack frame in which the call is being evaluated.
|
||||
const StackFrame *getStackFrame() const { return SF; }
|
||||
|
||||
const CFGBlock::ConstCFGElementRef &getCFGElementRef() const {
|
||||
return ElemRef;
|
||||
|
|
@ -433,7 +432,7 @@ public:
|
|||
bool isArgumentConstructedDirectly(unsigned Index) const {
|
||||
// This assumes that the object was not yet removed from the state.
|
||||
return ExprEngine::getObjectUnderConstruction(
|
||||
getState(), {getOriginExpr(), Index}, getLocationContext())
|
||||
getState(), {getOriginExpr(), Index}, getStackFrame())
|
||||
.has_value();
|
||||
}
|
||||
|
||||
|
|
@ -509,14 +508,12 @@ public:
|
|||
/// FunctionDecl.
|
||||
class AnyFunctionCall : public CallEvent {
|
||||
protected:
|
||||
AnyFunctionCall(const Expr *E, ProgramStateRef St,
|
||||
const LocationContext *LCtx,
|
||||
AnyFunctionCall(const Expr *E, ProgramStateRef St, const StackFrame *SF,
|
||||
CFGBlock::ConstCFGElementRef ElemRef)
|
||||
: CallEvent(E, St, LCtx, ElemRef) {}
|
||||
AnyFunctionCall(const Decl *D, ProgramStateRef St,
|
||||
const LocationContext *LCtx,
|
||||
: CallEvent(E, St, SF, ElemRef) {}
|
||||
AnyFunctionCall(const Decl *D, ProgramStateRef St, const StackFrame *SF,
|
||||
CFGBlock::ConstCFGElementRef ElemRef)
|
||||
: CallEvent(D, St, LCtx, ElemRef) {}
|
||||
: CallEvent(D, St, SF, ElemRef) {}
|
||||
AnyFunctionCall(const AnyFunctionCall &Other) = default;
|
||||
|
||||
public:
|
||||
|
|
@ -549,9 +546,8 @@ class SimpleFunctionCall : public AnyFunctionCall {
|
|||
|
||||
protected:
|
||||
SimpleFunctionCall(const CallExpr *CE, ProgramStateRef St,
|
||||
const LocationContext *LCtx,
|
||||
CFGBlock::ConstCFGElementRef ElemRef)
|
||||
: AnyFunctionCall(CE, St, LCtx, ElemRef) {}
|
||||
const StackFrame *SF, CFGBlock::ConstCFGElementRef ElemRef)
|
||||
: AnyFunctionCall(CE, St, SF, ElemRef) {}
|
||||
SimpleFunctionCall(const SimpleFunctionCall &Other) = default;
|
||||
|
||||
void cloneTo(void *Dest) const override {
|
||||
|
|
@ -588,9 +584,9 @@ class BlockCall : public CallEvent {
|
|||
friend class CallEventManager;
|
||||
|
||||
protected:
|
||||
BlockCall(const CallExpr *CE, ProgramStateRef St, const LocationContext *LCtx,
|
||||
BlockCall(const CallExpr *CE, ProgramStateRef St, const StackFrame *SF,
|
||||
CFGBlock::ConstCFGElementRef ElemRef)
|
||||
: CallEvent(CE, St, LCtx, ElemRef) {}
|
||||
: CallEvent(CE, St, SF, ElemRef) {}
|
||||
BlockCall(const BlockCall &Other) = default;
|
||||
|
||||
void cloneTo(void *Dest) const override { new (Dest) BlockCall(*this); }
|
||||
|
|
@ -689,14 +685,12 @@ public:
|
|||
/// it is written.
|
||||
class CXXInstanceCall : public AnyFunctionCall {
|
||||
protected:
|
||||
CXXInstanceCall(const CallExpr *CE, ProgramStateRef St,
|
||||
const LocationContext *LCtx,
|
||||
CXXInstanceCall(const CallExpr *CE, ProgramStateRef St, const StackFrame *SF,
|
||||
CFGBlock::ConstCFGElementRef ElemRef)
|
||||
: AnyFunctionCall(CE, St, LCtx, ElemRef) {}
|
||||
: AnyFunctionCall(CE, St, SF, ElemRef) {}
|
||||
CXXInstanceCall(const FunctionDecl *D, ProgramStateRef St,
|
||||
const LocationContext *LCtx,
|
||||
CFGBlock::ConstCFGElementRef ElemRef)
|
||||
: AnyFunctionCall(D, St, LCtx, ElemRef) {}
|
||||
const StackFrame *SF, CFGBlock::ConstCFGElementRef ElemRef)
|
||||
: AnyFunctionCall(D, St, SF, ElemRef) {}
|
||||
CXXInstanceCall(const CXXInstanceCall &Other) = default;
|
||||
|
||||
void getExtraInvalidatedValues(
|
||||
|
|
@ -749,9 +743,9 @@ class CXXStaticOperatorCall : public SimpleFunctionCall {
|
|||
|
||||
protected:
|
||||
CXXStaticOperatorCall(const CXXOperatorCallExpr *CE, ProgramStateRef St,
|
||||
const LocationContext *LCtx,
|
||||
const StackFrame *SF,
|
||||
CFGBlock::ConstCFGElementRef ElemRef)
|
||||
: SimpleFunctionCall(CE, St, LCtx, ElemRef) {}
|
||||
: SimpleFunctionCall(CE, St, SF, ElemRef) {}
|
||||
CXXStaticOperatorCall(const CXXStaticOperatorCall &Other) = default;
|
||||
|
||||
void cloneTo(void *Dest) const override {
|
||||
|
|
@ -807,9 +801,8 @@ class CXXMemberCall : public CXXInstanceCall {
|
|||
|
||||
protected:
|
||||
CXXMemberCall(const CXXMemberCallExpr *CE, ProgramStateRef St,
|
||||
const LocationContext *LCtx,
|
||||
CFGBlock::ConstCFGElementRef ElemRef)
|
||||
: CXXInstanceCall(CE, St, LCtx, ElemRef) {}
|
||||
const StackFrame *SF, CFGBlock::ConstCFGElementRef ElemRef)
|
||||
: CXXInstanceCall(CE, St, SF, ElemRef) {}
|
||||
CXXMemberCall(const CXXMemberCall &Other) = default;
|
||||
|
||||
void cloneTo(void *Dest) const override { new (Dest) CXXMemberCall(*this); }
|
||||
|
|
@ -850,9 +843,9 @@ class CXXMemberOperatorCall : public CXXInstanceCall {
|
|||
|
||||
protected:
|
||||
CXXMemberOperatorCall(const CXXOperatorCallExpr *CE, ProgramStateRef St,
|
||||
const LocationContext *LCtx,
|
||||
const StackFrame *SF,
|
||||
CFGBlock::ConstCFGElementRef ElemRef)
|
||||
: CXXInstanceCall(CE, St, LCtx, ElemRef) {}
|
||||
: CXXInstanceCall(CE, St, SF, ElemRef) {}
|
||||
CXXMemberOperatorCall(const CXXMemberOperatorCall &Other) = default;
|
||||
|
||||
void cloneTo(void *Dest) const override {
|
||||
|
|
@ -917,7 +910,7 @@ protected:
|
|||
/// \param Trigger The statement whose completion causes this destructor call.
|
||||
/// \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 SF The stack frame 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
|
||||
|
|
@ -926,9 +919,9 @@ protected:
|
|||
/// independent from ExprEngine.
|
||||
CXXDestructorCall(const CXXDestructorDecl *DD, const Stmt *Trigger,
|
||||
const MemRegion *Target, bool IsBaseDestructor,
|
||||
ProgramStateRef St, const LocationContext *LCtx,
|
||||
ProgramStateRef St, const StackFrame *SF,
|
||||
CFGBlock::ConstCFGElementRef ElemRef)
|
||||
: CXXInstanceCall(DD, St, LCtx, ElemRef) {
|
||||
: CXXInstanceCall(DD, St, SF, ElemRef) {
|
||||
Data = DtorDataTy(Target, IsBaseDestructor).getOpaqueValue();
|
||||
Location = Trigger->getEndLoc();
|
||||
}
|
||||
|
|
@ -966,9 +959,9 @@ public:
|
|||
class AnyCXXConstructorCall : public AnyFunctionCall {
|
||||
protected:
|
||||
AnyCXXConstructorCall(const Expr *E, const MemRegion *Target,
|
||||
ProgramStateRef St, const LocationContext *LCtx,
|
||||
ProgramStateRef St, const StackFrame *SF,
|
||||
CFGBlock::ConstCFGElementRef ElemRef)
|
||||
: AnyFunctionCall(E, St, LCtx, ElemRef) {
|
||||
: AnyFunctionCall(E, St, SF, ElemRef) {
|
||||
assert(E && (isa<CXXConstructExpr>(E) || isa<CXXInheritedCtorInitExpr>(E)));
|
||||
// Target may be null when the region is unknown.
|
||||
Data = Target;
|
||||
|
|
@ -1004,15 +997,15 @@ protected:
|
|||
/// \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.
|
||||
/// \param SF The stack frame 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,
|
||||
ProgramStateRef St, const StackFrame *SF,
|
||||
CFGBlock::ConstCFGElementRef ElemRef)
|
||||
: AnyCXXConstructorCall(CE, Target, St, LCtx, ElemRef) {}
|
||||
: AnyCXXConstructorCall(CE, Target, St, SF, ElemRef) {}
|
||||
|
||||
CXXConstructorCall(const CXXConstructorCall &Other) = default;
|
||||
|
||||
|
|
@ -1069,9 +1062,9 @@ class CXXInheritedConstructorCall : public AnyCXXConstructorCall {
|
|||
protected:
|
||||
CXXInheritedConstructorCall(const CXXInheritedCtorInitExpr *CE,
|
||||
const MemRegion *Target, ProgramStateRef St,
|
||||
const LocationContext *LCtx,
|
||||
const StackFrame *SF,
|
||||
CFGBlock::ConstCFGElementRef ElemRef)
|
||||
: AnyCXXConstructorCall(CE, Target, St, LCtx, ElemRef) {}
|
||||
: AnyCXXConstructorCall(CE, Target, St, SF, ElemRef) {}
|
||||
|
||||
CXXInheritedConstructorCall(const CXXInheritedConstructorCall &Other) =
|
||||
default;
|
||||
|
|
@ -1109,9 +1102,8 @@ public:
|
|||
}
|
||||
|
||||
SVal getArgSVal(unsigned Index) const override {
|
||||
return getState()->getSVal(
|
||||
getArgExpr(Index),
|
||||
getInheritingStackFrame()->getParent()->getStackFrame());
|
||||
return getState()->getSVal(getArgExpr(Index),
|
||||
getInheritingStackFrame()->getParent());
|
||||
}
|
||||
|
||||
Kind getKind() const override { return CE_CXXInheritedConstructor; }
|
||||
|
|
@ -1132,9 +1124,8 @@ class CXXAllocatorCall : public AnyFunctionCall {
|
|||
|
||||
protected:
|
||||
CXXAllocatorCall(const CXXNewExpr *E, ProgramStateRef St,
|
||||
const LocationContext *LCtx,
|
||||
CFGBlock::ConstCFGElementRef ElemRef)
|
||||
: AnyFunctionCall(E, St, LCtx, ElemRef) {}
|
||||
const StackFrame *SF, CFGBlock::ConstCFGElementRef ElemRef)
|
||||
: AnyFunctionCall(E, St, SF, ElemRef) {}
|
||||
CXXAllocatorCall(const CXXAllocatorCall &Other) = default;
|
||||
|
||||
void cloneTo(void *Dest) const override {
|
||||
|
|
@ -1152,7 +1143,7 @@ public:
|
|||
|
||||
SVal getObjectUnderConstruction() const {
|
||||
return *ExprEngine::getObjectUnderConstruction(getState(), getOriginExpr(),
|
||||
getLocationContext());
|
||||
getStackFrame());
|
||||
}
|
||||
|
||||
/// Number of non-placement arguments to the call. It is equal to 2 for
|
||||
|
|
@ -1175,7 +1166,7 @@ public:
|
|||
SVal getArraySizeVal() const {
|
||||
assert(isArray() && "The allocator call doesn't allocate and array!");
|
||||
|
||||
return getState()->getSVal(*getArraySizeExpr(), getLocationContext());
|
||||
return getState()->getSVal(*getArraySizeExpr(), getStackFrame());
|
||||
}
|
||||
|
||||
const Expr *getArgExpr(unsigned Index) const override {
|
||||
|
|
@ -1216,9 +1207,8 @@ class CXXDeallocatorCall : public AnyFunctionCall {
|
|||
|
||||
protected:
|
||||
CXXDeallocatorCall(const CXXDeleteExpr *E, ProgramStateRef St,
|
||||
const LocationContext *LCtx,
|
||||
CFGBlock::ConstCFGElementRef ElemRef)
|
||||
: AnyFunctionCall(E, St, LCtx, ElemRef) {}
|
||||
const StackFrame *SF, CFGBlock::ConstCFGElementRef ElemRef)
|
||||
: AnyFunctionCall(E, St, SF, ElemRef) {}
|
||||
CXXDeallocatorCall(const CXXDeallocatorCall &Other) = default;
|
||||
|
||||
void cloneTo(void *Dest) const override {
|
||||
|
|
@ -1265,9 +1255,8 @@ class ObjCMethodCall : public CallEvent {
|
|||
|
||||
protected:
|
||||
ObjCMethodCall(const ObjCMessageExpr *Msg, ProgramStateRef St,
|
||||
const LocationContext *LCtx,
|
||||
CFGBlock::ConstCFGElementRef ElemRef)
|
||||
: CallEvent(Msg, St, LCtx, ElemRef) {
|
||||
const StackFrame *SF, CFGBlock::ConstCFGElementRef ElemRef)
|
||||
: CallEvent(Msg, St, SF, ElemRef) {
|
||||
Data = nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -1392,36 +1381,36 @@ class CallEventManager {
|
|||
}
|
||||
|
||||
template <typename T, typename Arg>
|
||||
T *create(Arg A, ProgramStateRef St, const LocationContext *LCtx,
|
||||
T *create(Arg A, ProgramStateRef St, const StackFrame *SF,
|
||||
CFGBlock::ConstCFGElementRef ElemRef) {
|
||||
static_assert(sizeof(T) == sizeof(CallEventTemplateTy),
|
||||
"CallEvent subclasses are not all the same size");
|
||||
return new (allocate()) T(A, St, LCtx, ElemRef);
|
||||
return new (allocate()) T(A, St, SF, 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 StackFrame *SF,
|
||||
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, ElemRef);
|
||||
return new (allocate()) T(A1, A2, St, SF, ElemRef);
|
||||
}
|
||||
|
||||
template <typename T, typename Arg1, typename Arg2, typename Arg3>
|
||||
T *create(Arg1 A1, Arg2 A2, Arg3 A3, ProgramStateRef St,
|
||||
const LocationContext *LCtx, CFGBlock::ConstCFGElementRef ElemRef) {
|
||||
T *create(Arg1 A1, Arg2 A2, Arg3 A3, ProgramStateRef St, const StackFrame *SF,
|
||||
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, ElemRef);
|
||||
return new (allocate()) T(A1, A2, A3, St, SF, 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, CFGBlock::ConstCFGElementRef ElemRef) {
|
||||
const StackFrame *SF, 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, ElemRef);
|
||||
return new (allocate()) T(A1, A2, A3, A4, St, SF, ElemRef);
|
||||
}
|
||||
|
||||
public:
|
||||
|
|
@ -1433,56 +1422,56 @@ 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,
|
||||
const StackFrame *SF,
|
||||
CFGBlock::ConstCFGElementRef ElemRef);
|
||||
|
||||
CallEventRef<> getSimpleCall(const CallExpr *E, ProgramStateRef State,
|
||||
const LocationContext *LCtx,
|
||||
const StackFrame *SF,
|
||||
CFGBlock::ConstCFGElementRef ElemRef);
|
||||
|
||||
CallEventRef<ObjCMethodCall>
|
||||
getObjCMethodCall(const ObjCMessageExpr *E, ProgramStateRef State,
|
||||
const LocationContext *LCtx,
|
||||
const StackFrame *SF,
|
||||
CFGBlock::ConstCFGElementRef ElemRef) {
|
||||
return create<ObjCMethodCall>(E, State, LCtx, ElemRef);
|
||||
return create<ObjCMethodCall>(E, State, SF, ElemRef);
|
||||
}
|
||||
|
||||
CallEventRef<CXXConstructorCall>
|
||||
getCXXConstructorCall(const CXXConstructExpr *E, const MemRegion *Target,
|
||||
ProgramStateRef State, const LocationContext *LCtx,
|
||||
ProgramStateRef State, const StackFrame *SF,
|
||||
CFGBlock::ConstCFGElementRef ElemRef) {
|
||||
return create<CXXConstructorCall>(E, Target, State, LCtx, ElemRef);
|
||||
return create<CXXConstructorCall>(E, Target, State, SF, ElemRef);
|
||||
}
|
||||
|
||||
CallEventRef<CXXInheritedConstructorCall>
|
||||
getCXXInheritedConstructorCall(const CXXInheritedCtorInitExpr *E,
|
||||
const MemRegion *Target, ProgramStateRef State,
|
||||
const LocationContext *LCtx,
|
||||
const StackFrame *SF,
|
||||
CFGBlock::ConstCFGElementRef ElemRef) {
|
||||
return create<CXXInheritedConstructorCall>(E, Target, State, LCtx, ElemRef);
|
||||
return create<CXXInheritedConstructorCall>(E, Target, State, SF, ElemRef);
|
||||
}
|
||||
|
||||
CallEventRef<CXXDestructorCall>
|
||||
getCXXDestructorCall(const CXXDestructorDecl *DD, const Stmt *Trigger,
|
||||
const MemRegion *Target, bool IsBase,
|
||||
ProgramStateRef State, const LocationContext *LCtx,
|
||||
ProgramStateRef State, const StackFrame *SF,
|
||||
CFGBlock::ConstCFGElementRef ElemRef) {
|
||||
return create<CXXDestructorCall>(DD, Trigger, Target, IsBase, State, LCtx,
|
||||
return create<CXXDestructorCall>(DD, Trigger, Target, IsBase, State, SF,
|
||||
ElemRef);
|
||||
}
|
||||
|
||||
CallEventRef<CXXAllocatorCall>
|
||||
getCXXAllocatorCall(const CXXNewExpr *E, ProgramStateRef State,
|
||||
const LocationContext *LCtx,
|
||||
const StackFrame *SF,
|
||||
CFGBlock::ConstCFGElementRef ElemRef) {
|
||||
return create<CXXAllocatorCall>(E, State, LCtx, ElemRef);
|
||||
return create<CXXAllocatorCall>(E, State, SF, ElemRef);
|
||||
}
|
||||
|
||||
CallEventRef<CXXDeallocatorCall>
|
||||
getCXXDeallocatorCall(const CXXDeleteExpr *E, ProgramStateRef State,
|
||||
const LocationContext *LCtx,
|
||||
const StackFrame *SF,
|
||||
CFGBlock::ConstCFGElementRef ElemRef) {
|
||||
return create<CXXDeallocatorCall>(E, State, LCtx, ElemRef);
|
||||
return create<CXXDeallocatorCall>(E, State, SF, ElemRef);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -101,14 +101,10 @@ public:
|
|||
return Eng.getContext().getLangOpts();
|
||||
}
|
||||
|
||||
const LocationContext *getLocationContext() const {
|
||||
return Pred->getLocationContext();
|
||||
}
|
||||
|
||||
const StackFrame *getStackFrame() const { return Pred->getStackFrame(); }
|
||||
|
||||
/// Return true if the current LocationContext has no caller context.
|
||||
bool inTopFrame() const { return getLocationContext()->inTopFrame(); }
|
||||
/// Return true if the current StackFrame has no caller context.
|
||||
bool inTopFrame() const { return getStackFrame()->inTopFrame(); }
|
||||
|
||||
BugReporter &getBugReporter() {
|
||||
return Eng.getBugReporter();
|
||||
|
|
@ -147,7 +143,7 @@ public:
|
|||
}
|
||||
|
||||
AnalysisDeclContext *getCurrentAnalysisDeclContext() const {
|
||||
return Pred->getLocationContext()->getAnalysisDeclContext();
|
||||
return Pred->getStackFrame()->getAnalysisDeclContext();
|
||||
}
|
||||
|
||||
/// Get the blockID.
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ public:
|
|||
|
||||
/// ExecuteWorkList - Run the worklist algorithm for a maximum number of
|
||||
/// steps. Returns true if there is still simulation state on the worklist.
|
||||
bool ExecuteWorkList(const LocationContext *L, unsigned Steps,
|
||||
bool ExecuteWorkList(const StackFrame *SF, unsigned Steps,
|
||||
ProgramStateRef InitState);
|
||||
|
||||
/// Dispatch the work list item based on the given location information.
|
||||
|
|
@ -173,7 +173,7 @@ public:
|
|||
ExplodedNode *makePostStmtNode(const Stmt *S, ProgramStateRef State,
|
||||
ExplodedNode *Pred,
|
||||
bool MarkAsSink = false) const {
|
||||
PostStmt Loc(S, Pred->getLocationContext(), /*tag=*/nullptr);
|
||||
PostStmt Loc(S, Pred->getStackFrame(), /*tag=*/nullptr);
|
||||
return makeNode(Loc, State, Pred, MarkAsSink);
|
||||
}
|
||||
|
||||
|
|
@ -181,9 +181,9 @@ public:
|
|||
makeNodeWithBinding(ExplodedNode *Pred, const Expr *E, SVal V,
|
||||
ProgramStateRef State,
|
||||
ProgramPoint::Kind K = ProgramPoint::PostStmtKind) const {
|
||||
const LocationContext *LC = Pred->getLocationContext();
|
||||
State = State->BindExpr(E, LC, V);
|
||||
const auto &L = ProgramPoint::getProgramPoint(E, K, LC, /*tag=*/nullptr);
|
||||
const StackFrame *SF = Pred->getStackFrame();
|
||||
State = State->BindExpr(E, SF, V);
|
||||
const auto &L = ProgramPoint::getProgramPoint(E, K, SF, /*tag=*/nullptr);
|
||||
return makeNode(L, State, Pred);
|
||||
}
|
||||
|
||||
|
|
@ -214,17 +214,17 @@ public:
|
|||
class NodeBuilderContext {
|
||||
const CoreEngine &Eng;
|
||||
const CFGBlock *Block;
|
||||
const LocationContext *LC;
|
||||
const StackFrame *SF;
|
||||
|
||||
public:
|
||||
NodeBuilderContext(const CoreEngine &E, const CFGBlock *B,
|
||||
const LocationContext *L)
|
||||
: Eng(E), Block(B), LC(L) {
|
||||
const StackFrame *S)
|
||||
: Eng(E), Block(B), SF(S) {
|
||||
assert(B);
|
||||
}
|
||||
|
||||
NodeBuilderContext(const CoreEngine &E, const CFGBlock *B, ExplodedNode *N)
|
||||
: NodeBuilderContext(E, B, N->getLocationContext()) {}
|
||||
: NodeBuilderContext(E, B, N->getStackFrame()) {}
|
||||
|
||||
/// Return the CoreEngine associated with this builder.
|
||||
const CoreEngine &getEngine() const { return Eng; }
|
||||
|
|
@ -232,15 +232,13 @@ public:
|
|||
/// Return the CFGBlock associated with this builder.
|
||||
const CFGBlock *getBlock() const { return Block; }
|
||||
|
||||
/// Return the location context associated with this builder.
|
||||
const LocationContext *getLocationContext() const { return LC; }
|
||||
/// Return the stack frame associated with this builder.
|
||||
const StackFrame *getStackFrame() const { return SF; }
|
||||
|
||||
/// Returns the number of times the current basic block has been
|
||||
/// visited on the exploded graph path.
|
||||
unsigned blockCount() const {
|
||||
return Eng.WList->getBlockCounter().getNumVisited(
|
||||
LC->getStackFrame(),
|
||||
Block->getBlockID());
|
||||
return Eng.WList->getBlockCounter().getNumVisited(SF, Block->getBlockID());
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -310,8 +308,8 @@ public:
|
|||
ProgramStateRef St,
|
||||
const ProgramPointTag *tag = nullptr,
|
||||
ProgramPoint::Kind K = ProgramPoint::PostStmtKind){
|
||||
const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
|
||||
Pred->getLocationContext(), tag);
|
||||
const ProgramPoint &L =
|
||||
ProgramPoint::getProgramPoint(S, K, Pred->getStackFrame(), tag);
|
||||
return generateNode(L, St, Pred);
|
||||
}
|
||||
|
||||
|
|
@ -320,8 +318,8 @@ public:
|
|||
ProgramStateRef St,
|
||||
const ProgramPointTag *tag = nullptr,
|
||||
ProgramPoint::Kind K = ProgramPoint::PostStmtKind){
|
||||
const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
|
||||
Pred->getLocationContext(), tag);
|
||||
const ProgramPoint &L =
|
||||
ProgramPoint::getProgramPoint(S, K, Pred->getStackFrame(), tag);
|
||||
return generateSink(L, St, Pred);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,22 +28,22 @@ namespace ento {
|
|||
class SValBuilder;
|
||||
class SymbolReaper;
|
||||
|
||||
/// An entry in the environment consists of a Stmt and an LocationContext.
|
||||
/// An entry in the environment consists of a Stmt and an StackFrame.
|
||||
/// This allows the environment to manage context-sensitive bindings,
|
||||
/// which is essentially for modeling recursive function analysis, among
|
||||
/// other things.
|
||||
class EnvironmentEntry : public std::pair<const Expr *, const StackFrame *> {
|
||||
public:
|
||||
EnvironmentEntry(const Expr *E, const LocationContext *L);
|
||||
EnvironmentEntry(const Expr *E, const StackFrame *SF);
|
||||
|
||||
const Expr *getExpr() const { return first; }
|
||||
const LocationContext *getLocationContext() const { return second; }
|
||||
const StackFrame *getStackFrame() const { return second; }
|
||||
|
||||
/// Profile an EnvironmentEntry for inclusion in a FoldingSet.
|
||||
static void Profile(llvm::FoldingSetNodeID &ID,
|
||||
const EnvironmentEntry &E) {
|
||||
ID.AddPointer(E.getExpr());
|
||||
ID.AddPointer(E.getLocationContext());
|
||||
ID.AddPointer(E.getStackFrame());
|
||||
}
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) const {
|
||||
|
|
@ -91,7 +91,7 @@ public:
|
|||
}
|
||||
|
||||
void printJson(raw_ostream &Out, const ASTContext &Ctx,
|
||||
const LocationContext *LCtx = nullptr, const char *NL = "\n",
|
||||
const StackFrame *SF = nullptr, const char *NL = "\n",
|
||||
unsigned int Space = 0, bool IsDot = false) const;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -140,26 +140,22 @@ public:
|
|||
/// getLocation - Returns the edge associated with the given node.
|
||||
ProgramPoint getLocation() const { return Location; }
|
||||
|
||||
const LocationContext *getLocationContext() const {
|
||||
return getLocation().getLocationContext();
|
||||
}
|
||||
|
||||
const StackFrame *getStackFrame() const {
|
||||
return getLocation().getStackFrame();
|
||||
}
|
||||
|
||||
const Decl &getCodeDecl() const { return *getLocationContext()->getDecl(); }
|
||||
const Decl &getCodeDecl() const { return *getStackFrame()->getDecl(); }
|
||||
|
||||
CFG &getCFG() const { return *getLocationContext()->getCFG(); }
|
||||
CFG &getCFG() const { return *getStackFrame()->getCFG(); }
|
||||
|
||||
const CFGBlock *getCFGBlock() const;
|
||||
|
||||
const ParentMap &getParentMap() const {
|
||||
return getLocationContext()->getParentMap();
|
||||
return getStackFrame()->getParentMap();
|
||||
}
|
||||
|
||||
template <typename T> T &getAnalysis() const {
|
||||
return *getLocationContext()->getAnalysis<T>();
|
||||
return *getStackFrame()->getAnalysis<T>();
|
||||
}
|
||||
|
||||
const ProgramStateRef &getState() const { return State; }
|
||||
|
|
@ -170,7 +166,7 @@ public:
|
|||
|
||||
/// Get the value of an arbitrary expression at this node.
|
||||
SVal getSVal(const Expr *E) const {
|
||||
return getState()->getSVal(E, getLocationContext());
|
||||
return getState()->getSVal(E, getStackFrame());
|
||||
}
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &ID,
|
||||
|
|
|
|||
|
|
@ -57,7 +57,6 @@ class Decl;
|
|||
class DeclStmt;
|
||||
class GCCAsmStmt;
|
||||
class LambdaExpr;
|
||||
class LocationContext;
|
||||
class MaterializeTemporaryExpr;
|
||||
class MSAsmStmt;
|
||||
class NamedDecl;
|
||||
|
|
@ -162,22 +161,22 @@ private:
|
|||
/// which has three independent roles:
|
||||
/// - It holds a pointer to the CFGBlock that is currently under analysis.
|
||||
/// (This is the primary way to get the current block.)
|
||||
/// - It holds a pointer to the current LocationContext. (This is rarely
|
||||
/// used, the location context is usually queried from a recent
|
||||
/// - It holds a pointer to the current StackFrame. (This is rarely
|
||||
/// used, the stack frame is usually queried from a recent
|
||||
/// ExplodedNode. Unfortunately it seems that these two sources of truth
|
||||
/// are not always consistent.)
|
||||
/// - It can be used for constructing `NodeBuilder`s. Practically all
|
||||
/// `NodeBuilder` objects are useless complications in the code, so I
|
||||
/// intend to replace them with direct use of `CoreEngine::makeNode`.
|
||||
/// TODO: Eventually `currBldrCtx` should be replaced by two separate fields:
|
||||
/// `const CFGBlock *CurrBlock` & `const LocationContext *CurrLocationContext`
|
||||
/// `const CFGBlock *CurrBlock` & `const StackFrame *CurrStackFrame`
|
||||
/// that are kept up-to-date and are almost always non-null during the
|
||||
/// analysis. I will switch to this more natural representation when
|
||||
/// `NodeBuilder`s are eliminated from the code.
|
||||
const NodeBuilderContext *currBldrCtx = nullptr;
|
||||
/// Historically `currBldrCtx` pointed to a local variable in some stack
|
||||
/// frame. This field is introduced as a temporary measure to allow a gradual
|
||||
/// transition. Only use this in {re,}setLocationContextAndBlock!
|
||||
/// transition. Only use this in {re,}setCurrStackFrameAndBlock!
|
||||
/// TODO: Remove this temporary hack.
|
||||
std::optional<NodeBuilderContext> OwnedCurrBldrCtx;
|
||||
|
||||
|
|
@ -205,10 +204,10 @@ public:
|
|||
virtual ~ExprEngine() = default;
|
||||
|
||||
/// Returns true if there is still simulation state on the worklist.
|
||||
bool ExecuteWorkList(const LocationContext *L, unsigned Steps = 150000) {
|
||||
assert(L->inTopFrame());
|
||||
BR.setAnalysisEntryPoint(L->getDecl());
|
||||
return Engine.ExecuteWorkList(L, Steps, nullptr);
|
||||
bool ExecuteWorkList(const StackFrame *SF, unsigned Steps = 150000) {
|
||||
assert(SF->inTopFrame());
|
||||
BR.setAnalysisEntryPoint(SF->getDecl());
|
||||
return Engine.ExecuteWorkList(SF, Steps, nullptr);
|
||||
}
|
||||
|
||||
/// getContext - Return the ASTContext associated with this analysis.
|
||||
|
|
@ -237,27 +236,26 @@ public:
|
|||
}
|
||||
|
||||
// FIXME: Ideally the body of this method should look like
|
||||
// CurrLocationContext = LC;
|
||||
// CurrStackFrame = SF;
|
||||
// CurrBlock = B;
|
||||
// where CurrLocationContext and CurrBlock are new member variables that
|
||||
// where CurrStackFrame and CurrBlock are new member variables that
|
||||
// fulfill the roles of `currBldrCtx` in a more natural way.
|
||||
// This implementation is a temporary measure to allow a gradual transition.
|
||||
void setCurrLocationContextAndBlock(const LocationContext *LC,
|
||||
const CFGBlock *B) {
|
||||
// The current LocationContext and Block is reset at the beginning of
|
||||
void setCurrStackFrameAndBlock(const StackFrame *SF, const CFGBlock *B) {
|
||||
// The current StackFrame and Block is reset at the beginning of
|
||||
// dispatchWorkItem. Ideally, this method should be called only once per
|
||||
// dispatchWorkItem call (= elementary analysis step); so the following
|
||||
// assertion is there to catch accidental repeated calls. If the current
|
||||
// LocationContext and Block needs to change in the middle of a single step
|
||||
// StackFrame and Block needs to change in the middle of a single step
|
||||
// (which currently happens only once, in processCallExit), use an explicit
|
||||
// call to resetCurrLocationContextAndBlock.
|
||||
// call to resetCurrStackFrameAndBlock.
|
||||
assert(!currBldrCtx && !OwnedCurrBldrCtx &&
|
||||
"The current LocationContext and Block is already set");
|
||||
OwnedCurrBldrCtx.emplace(Engine, B, LC);
|
||||
"The current StackFrame and Block is already set");
|
||||
OwnedCurrBldrCtx.emplace(Engine, B, SF);
|
||||
currBldrCtx = &*OwnedCurrBldrCtx;
|
||||
}
|
||||
|
||||
void resetCurrLocationContextAndBlock() {
|
||||
void resetCurrStackFrameAndBlock() {
|
||||
currBldrCtx = nullptr;
|
||||
OwnedCurrBldrCtx = std::nullopt;
|
||||
}
|
||||
|
|
@ -267,20 +265,20 @@ public:
|
|||
return *currBldrCtx;
|
||||
}
|
||||
|
||||
const LocationContext *getRootLocationContext() const {
|
||||
const StackFrame *getRootStackFrame() const {
|
||||
assert(G.getRoot());
|
||||
return G.getRoot()->getLocation().getLocationContext();
|
||||
return G.getRoot()->getLocation().getStackFrame();
|
||||
}
|
||||
|
||||
/// Get the 'current' location context corresponding to the current work item
|
||||
/// Get the 'current' stack frame corresponding to the current work item
|
||||
/// (elementary analysis step handled by `dispatchWorkItem`).
|
||||
/// FIXME: This sometimes (e.g. in some `BeginFunction` callbacks) differs
|
||||
/// from the `LocationContext` that can be obtained from different sources
|
||||
/// (e.g. a recent `ExplodedNode`). Traditionally this location context is
|
||||
/// from the `StackFrame` that can be obtained from different sources
|
||||
/// (e.g. a recent `ExplodedNode`). Traditionally this stack frame is
|
||||
/// only used for block count calculations (`getNumVisited`); it is probably
|
||||
/// wise to follow this tradition until the discrepancies are resolved.
|
||||
const LocationContext *getCurrLocationContext() const {
|
||||
return currBldrCtx ? currBldrCtx->getLocationContext() : nullptr;
|
||||
const StackFrame *getCurrStackFrame() const {
|
||||
return currBldrCtx ? currBldrCtx->getStackFrame() : nullptr;
|
||||
}
|
||||
|
||||
/// Get the 'current' CFGBlock corresponding to the current work item
|
||||
|
|
@ -293,14 +291,13 @@ public:
|
|||
return {getCurrBlock(), currStmtIdx};
|
||||
}
|
||||
|
||||
unsigned getNumVisited(const LocationContext *LC,
|
||||
const CFGBlock *Block) const {
|
||||
return Engine.WList->getBlockCounter().getNumVisited(LC->getStackFrame(),
|
||||
unsigned getNumVisited(const StackFrame *SF, const CFGBlock *Block) const {
|
||||
return Engine.WList->getBlockCounter().getNumVisited(SF,
|
||||
Block->getBlockID());
|
||||
}
|
||||
|
||||
unsigned getNumVisitedCurrent() const {
|
||||
return getNumVisited(getCurrLocationContext(), getCurrBlock());
|
||||
return getNumVisited(getCurrStackFrame(), getCurrBlock());
|
||||
}
|
||||
|
||||
/// Dump graph to the specified filename.
|
||||
|
|
@ -323,7 +320,7 @@ public:
|
|||
|
||||
/// getInitialState - Return the initial state used for the root vertex
|
||||
/// in the ExplodedGraph.
|
||||
ProgramStateRef getInitialState(const LocationContext *InitLoc);
|
||||
ProgramStateRef getInitialState(const StackFrame *InitSF);
|
||||
|
||||
ExplodedGraph &getGraph() { return G; }
|
||||
const ExplodedGraph &getGraph() const { return G; }
|
||||
|
|
@ -339,24 +336,25 @@ public:
|
|||
/// \param Out The returned set of output nodes.
|
||||
/// \param ReferenceStmt The statement which is about to be processed.
|
||||
/// Everything needed for this statement should be considered live.
|
||||
/// A null statement means that everything in child LocationContexts
|
||||
/// A null statement means that everything in child StackFrames
|
||||
/// is dead.
|
||||
/// \param LC The location context of the \p ReferenceStmt. A null location
|
||||
/// context means that we have reached the end of analysis and that
|
||||
/// \param SF The stack frame of the \p ReferenceStmt. A null stack frame
|
||||
/// means that we have reached the end of analysis and that
|
||||
/// all statements and local variables should be considered dead.
|
||||
/// \param DiagnosticStmt Used as a location for any warnings that should
|
||||
/// occur while removing the dead (e.g. leaks). By default, the
|
||||
/// \p ReferenceStmt is used.
|
||||
/// \param K Denotes whether this is a pre- or post-statement purge. This
|
||||
/// must only be ProgramPoint::PostStmtPurgeDeadSymbolsKind if an
|
||||
/// entire location context is being cleared, in which case the
|
||||
/// entire stack frame is being cleared, in which case the
|
||||
/// \p ReferenceStmt must either be a ReturnStmt or \c NULL. Otherwise,
|
||||
/// it must be ProgramPoint::PreStmtPurgeDeadSymbolsKind (the default)
|
||||
/// and \p ReferenceStmt must be valid (non-null).
|
||||
void removeDead(ExplodedNode *Node, ExplodedNodeSet &Out,
|
||||
const Stmt *ReferenceStmt, const LocationContext *LC,
|
||||
const Stmt *DiagnosticStmt = nullptr,
|
||||
ProgramPoint::Kind K = ProgramPoint::PreStmtPurgeDeadSymbolsKind);
|
||||
void
|
||||
removeDead(ExplodedNode *Node, ExplodedNodeSet &Out,
|
||||
const Stmt *ReferenceStmt, const StackFrame *SF,
|
||||
const Stmt *DiagnosticStmt = nullptr,
|
||||
ProgramPoint::Kind K = ProgramPoint::PreStmtPurgeDeadSymbolsKind);
|
||||
|
||||
/// A tag to track convenience transitions, which can be removed at cleanup.
|
||||
/// This tag applies to a node created after removeDead.
|
||||
|
|
@ -462,20 +460,17 @@ public:
|
|||
const InvalidatedSymbols *invalidated,
|
||||
ArrayRef<const MemRegion *> ExplicitRegions,
|
||||
ArrayRef<const MemRegion *> Regions,
|
||||
const LocationContext *LCtx,
|
||||
const CallEvent *Call);
|
||||
const StackFrame *SF, const CallEvent *Call);
|
||||
|
||||
inline ProgramStateRef
|
||||
processRegionChange(ProgramStateRef state,
|
||||
const MemRegion* MR,
|
||||
const LocationContext *LCtx) {
|
||||
return processRegionChanges(state, nullptr, MR, MR, LCtx, nullptr);
|
||||
inline ProgramStateRef processRegionChange(ProgramStateRef state,
|
||||
const MemRegion *MR,
|
||||
const StackFrame *SF) {
|
||||
return processRegionChanges(state, nullptr, MR, MR, SF, nullptr);
|
||||
}
|
||||
|
||||
/// printJson - Called by ProgramStateManager to print checker-specific data.
|
||||
void printJson(raw_ostream &Out, ProgramStateRef State,
|
||||
const LocationContext *LCtx, const char *NL,
|
||||
unsigned int Space, bool IsDot) const;
|
||||
void printJson(raw_ostream &Out, ProgramStateRef State, const StackFrame *SF,
|
||||
const char *NL, unsigned int Space, bool IsDot) const;
|
||||
|
||||
ProgramStateManager &getStateManager() { return StateMgr; }
|
||||
const ProgramStateManager &getStateManager() const { return StateMgr; }
|
||||
|
|
@ -673,7 +668,7 @@ public:
|
|||
getEagerlyAssumeBifurcationTags();
|
||||
|
||||
ProgramStateRef handleLValueBitCast(ProgramStateRef state, const Expr *Ex,
|
||||
const LocationContext *LCtx, QualType T,
|
||||
const StackFrame *SF, QualType T,
|
||||
QualType ExTy, const CastExpr *CastE,
|
||||
NodeBuilder &Bldr, ExplodedNode *Pred);
|
||||
|
||||
|
|
@ -689,17 +684,16 @@ public:
|
|||
/// Retrieves which element is being constructed in a non-POD type array.
|
||||
static std::optional<unsigned>
|
||||
getIndexOfElementToConstruct(ProgramStateRef State, const CXXConstructExpr *E,
|
||||
const LocationContext *LCtx);
|
||||
const StackFrame *SF);
|
||||
|
||||
/// Retrieves which element is being destructed in a non-POD type array.
|
||||
static std::optional<unsigned>
|
||||
getPendingArrayDestruction(ProgramStateRef State,
|
||||
const LocationContext *LCtx);
|
||||
getPendingArrayDestruction(ProgramStateRef State, const StackFrame *SF);
|
||||
|
||||
/// Retrieves the size of the array in the pending ArrayInitLoopExpr.
|
||||
static std::optional<unsigned>
|
||||
getPendingInitLoop(ProgramStateRef State, const CXXConstructExpr *E,
|
||||
const LocationContext *LCtx);
|
||||
static std::optional<unsigned> getPendingInitLoop(ProgramStateRef State,
|
||||
const CXXConstructExpr *E,
|
||||
const StackFrame *SF);
|
||||
|
||||
/// By looking at a certain item that may be potentially part of an object's
|
||||
/// ConstructionContext, retrieve such object's location. A particular
|
||||
|
|
@ -707,13 +701,12 @@ public:
|
|||
static std::optional<SVal>
|
||||
getObjectUnderConstruction(ProgramStateRef State,
|
||||
const ConstructionContextItem &Item,
|
||||
const LocationContext *LC);
|
||||
const StackFrame *SF);
|
||||
|
||||
/// Call PointerEscape callback when a value escapes as a result of bind.
|
||||
ProgramStateRef processPointerEscapedOnBind(
|
||||
ProgramStateRef State, ArrayRef<std::pair<SVal, SVal>> LocAndVals,
|
||||
const LocationContext *LCtx, PointerEscapeKind Kind,
|
||||
const CallEvent *Call);
|
||||
const StackFrame *SF, PointerEscapeKind Kind, const CallEvent *Call);
|
||||
|
||||
/// Call PointerEscape callback when a value escapes as a result of
|
||||
/// region invalidation.
|
||||
|
|
@ -732,10 +725,8 @@ private:
|
|||
SVal location, SVal Val, bool AtDeclInit = false,
|
||||
const ProgramPoint *PP = nullptr);
|
||||
|
||||
ProgramStateRef
|
||||
processPointerEscapedOnBind(ProgramStateRef State,
|
||||
SVal Loc, SVal Val,
|
||||
const LocationContext *LCtx);
|
||||
ProgramStateRef processPointerEscapedOnBind(ProgramStateRef State, SVal Loc,
|
||||
SVal Val, const StackFrame *SF);
|
||||
|
||||
public:
|
||||
/// A simple wrapper when you only need to notify checkers of pointer-escape
|
||||
|
|
@ -744,7 +735,7 @@ public:
|
|||
PointerEscapeKind K,
|
||||
const CallEvent *Call = nullptr) const;
|
||||
|
||||
// FIXME: 'tag' should be removed, and a LocationContext should be used
|
||||
// FIXME: 'tag' should be removed, and a StackFrame should be used
|
||||
// instead.
|
||||
// FIXME: Comment on the meaning of the arguments, when 'St' may not
|
||||
// be the same as Pred->state, and when 'location' may not be the
|
||||
|
|
@ -759,7 +750,7 @@ public:
|
|||
const ProgramPointTag *tag = nullptr,
|
||||
QualType LoadTy = QualType());
|
||||
|
||||
// FIXME: 'tag' should be removed, and a LocationContext should be used
|
||||
// FIXME: 'tag' should be removed, and a StackFrame should be used
|
||||
// instead.
|
||||
void evalStore(ExplodedNodeSet &Dst, const Expr *AssignE, const Expr *StoreE,
|
||||
ExplodedNode *Pred, ProgramStateRef St, SVal TargetLV, SVal Val,
|
||||
|
|
@ -771,8 +762,7 @@ public:
|
|||
|
||||
/// Create a new state in which the call return value is binded to the
|
||||
/// call origin expression.
|
||||
ProgramStateRef bindReturnValue(const CallEvent &Call,
|
||||
const LocationContext *LCtx,
|
||||
ProgramStateRef bindReturnValue(const CallEvent &Call, const StackFrame *SF,
|
||||
ProgramStateRef State);
|
||||
|
||||
/// Evaluate a call, running pre- and post-call checkers and allowing checkers
|
||||
|
|
@ -800,7 +790,7 @@ public:
|
|||
/// row major order, so for arr[0][0] Idx is 0 and for arr[3][3] Idx is 8.
|
||||
SVal computeObjectUnderConstruction(const Expr *E, ProgramStateRef State,
|
||||
unsigned NumVisitedCaller,
|
||||
const LocationContext *LCtx,
|
||||
const StackFrame *SF,
|
||||
const ConstructionContext *CC,
|
||||
EvalCallOptions &CallOpts,
|
||||
unsigned Idx = 0);
|
||||
|
|
@ -809,21 +799,22 @@ public:
|
|||
/// that's necessary to perform construction of an object with a given
|
||||
/// syntactic construction context. V and CallOpts have to be obtained from
|
||||
/// computeObjectUnderConstruction() invoked with the same set of
|
||||
/// the remaining arguments (E, State, LCtx, CC).
|
||||
/// the remaining arguments (E, State, SF, CC).
|
||||
ProgramStateRef updateObjectsUnderConstruction(
|
||||
SVal V, const Expr *E, ProgramStateRef State, const LocationContext *LCtx,
|
||||
SVal V, const Expr *E, ProgramStateRef State, const StackFrame *SF,
|
||||
const ConstructionContext *CC, const EvalCallOptions &CallOpts);
|
||||
|
||||
/// A convenient wrapper around computeObjectUnderConstruction
|
||||
/// and updateObjectsUnderConstruction.
|
||||
std::pair<ProgramStateRef, SVal> handleConstructionContext(
|
||||
const Expr *E, ProgramStateRef State, const NodeBuilderContext *BldrCtx,
|
||||
const LocationContext *LCtx, const ConstructionContext *CC,
|
||||
EvalCallOptions &CallOpts, unsigned Idx = 0) {
|
||||
std::pair<ProgramStateRef, SVal>
|
||||
handleConstructionContext(const Expr *E, ProgramStateRef State,
|
||||
const NodeBuilderContext *BldrCtx,
|
||||
const StackFrame *SF, const ConstructionContext *CC,
|
||||
EvalCallOptions &CallOpts, unsigned Idx = 0) {
|
||||
|
||||
SVal V = computeObjectUnderConstruction(E, State, BldrCtx->blockCount(),
|
||||
LCtx, CC, CallOpts, Idx);
|
||||
State = updateObjectsUnderConstruction(V, E, State, LCtx, CC, CallOpts);
|
||||
SVal V = computeObjectUnderConstruction(E, State, BldrCtx->blockCount(), SF,
|
||||
CC, CallOpts, Idx);
|
||||
State = updateObjectsUnderConstruction(V, E, State, SF, CC, CallOpts);
|
||||
|
||||
return std::make_pair(State, V);
|
||||
}
|
||||
|
|
@ -843,7 +834,7 @@ private:
|
|||
bool isLoad);
|
||||
|
||||
/// Count the stack depth and determine if the call is recursive.
|
||||
void examineStackFrames(const Decl *D, const LocationContext *LCtx,
|
||||
void examineStackFrames(const Decl *D, const StackFrame *SF,
|
||||
bool &IsRecursive, unsigned &StackDepth);
|
||||
|
||||
enum CallInlinePolicy {
|
||||
|
|
@ -887,7 +878,7 @@ private:
|
|||
/// construction.
|
||||
bool shouldInlineArrayConstruction(const ProgramStateRef State,
|
||||
const CXXConstructExpr *CE,
|
||||
const LocationContext *LCtx);
|
||||
const StackFrame *SF);
|
||||
|
||||
/// Checks whether our policies allow us to inline a non-POD type array
|
||||
/// destruction.
|
||||
|
|
@ -901,19 +892,19 @@ private:
|
|||
/// original state along with an index of 0. The actual element count of the
|
||||
/// array can be accessed by the optional 'ElementCountVal' parameter. \param
|
||||
/// State The program state. \param Region The memory region where the array
|
||||
/// is stored. \param ElementTy The type an element in the array. \param LCty
|
||||
/// The location context. \param ElementCountVal A pointer to an optional
|
||||
/// SVal. If specified, the size of the array will be returned in it. It can
|
||||
/// is stored. \param ElementTy The type an element in the array. \param SF
|
||||
/// The stack frame. \param ElementCountVal A pointer to an optional SVal.
|
||||
/// If specified, the size of the array will be returned in it. It can
|
||||
/// be Unknown.
|
||||
std::pair<ProgramStateRef, uint64_t> prepareStateForArrayDestruction(
|
||||
const ProgramStateRef State, const MemRegion *Region,
|
||||
const QualType &ElementTy, const LocationContext *LCtx,
|
||||
const QualType &ElementTy, const StackFrame *SF,
|
||||
SVal *ElementCountVal = nullptr);
|
||||
|
||||
/// Checks whether we construct an array of non-POD type, and decides if the
|
||||
/// constructor should be invoked once again.
|
||||
bool shouldRepeatCtorCall(ProgramStateRef State, const CXXConstructExpr *E,
|
||||
const LocationContext *LCtx);
|
||||
const StackFrame *SF);
|
||||
|
||||
void inlineCall(WorkList *WList, const CallEvent &Call, const Decl *D,
|
||||
NodeBuilder &Bldr, ExplodedNode *Pred, ProgramStateRef State);
|
||||
|
|
@ -935,7 +926,7 @@ private:
|
|||
const CallEvent &Call, const Decl *D, NodeBuilder &Bldr,
|
||||
ExplodedNode *Pred);
|
||||
|
||||
bool replayWithoutInlining(ExplodedNode *P, const LocationContext *CalleeLC);
|
||||
bool replayWithoutInlining(ExplodedNode *P, const StackFrame *CalleeSF);
|
||||
|
||||
/// Models a trivial copy or move constructor or trivial assignment operator
|
||||
/// call with a simple bind.
|
||||
|
|
@ -953,7 +944,7 @@ private:
|
|||
/// OutRegionWithAdjustments out-parameter if a new region was indeed needed,
|
||||
/// otherwise sets it to nullptr.
|
||||
ProgramStateRef createTemporaryRegionIfNeeded(
|
||||
ProgramStateRef State, const LocationContext *LC,
|
||||
ProgramStateRef State, const StackFrame *SF,
|
||||
const Expr *InitWithAdjustments, const Expr *Result = nullptr,
|
||||
const SubRegion **OutRegionWithAdjustments = nullptr);
|
||||
|
||||
|
|
@ -980,52 +971,47 @@ public:
|
|||
[[nodiscard]] static ProgramStateRef
|
||||
setWhetherHasMoreIteration(ProgramStateRef State,
|
||||
const ObjCForCollectionStmt *O,
|
||||
const LocationContext *LC, bool HasMoreIteraton);
|
||||
const StackFrame *SF, bool HasMoreIteraton);
|
||||
|
||||
[[nodiscard]] static ProgramStateRef
|
||||
removeIterationState(ProgramStateRef State, const ObjCForCollectionStmt *O,
|
||||
const LocationContext *LC);
|
||||
const StackFrame *SF);
|
||||
|
||||
[[nodiscard]] static bool hasMoreIteration(ProgramStateRef State,
|
||||
const ObjCForCollectionStmt *O,
|
||||
const LocationContext *LC);
|
||||
const StackFrame *SF);
|
||||
|
||||
private:
|
||||
/// Assuming we construct an array of non-POD types, this method allows us
|
||||
/// to store which element is to be constructed next.
|
||||
static ProgramStateRef
|
||||
setIndexOfElementToConstruct(ProgramStateRef State, const CXXConstructExpr *E,
|
||||
const LocationContext *LCtx, unsigned Idx);
|
||||
static ProgramStateRef setIndexOfElementToConstruct(ProgramStateRef State,
|
||||
const CXXConstructExpr *E,
|
||||
const StackFrame *SF,
|
||||
unsigned Idx);
|
||||
|
||||
static ProgramStateRef
|
||||
removeIndexOfElementToConstruct(ProgramStateRef State,
|
||||
const CXXConstructExpr *E,
|
||||
const LocationContext *LCtx);
|
||||
static ProgramStateRef removeIndexOfElementToConstruct(
|
||||
ProgramStateRef State, const CXXConstructExpr *E, const StackFrame *SF);
|
||||
|
||||
/// Assuming we destruct an array of non-POD types, this method allows us
|
||||
/// to store which element is to be destructed next.
|
||||
static ProgramStateRef setPendingArrayDestruction(ProgramStateRef State,
|
||||
const LocationContext *LCtx,
|
||||
const StackFrame *SF,
|
||||
unsigned Idx);
|
||||
|
||||
static ProgramStateRef
|
||||
removePendingArrayDestruction(ProgramStateRef State,
|
||||
const LocationContext *LCtx);
|
||||
static ProgramStateRef removePendingArrayDestruction(ProgramStateRef State,
|
||||
const StackFrame *SF);
|
||||
|
||||
/// Sets the size of the array in a pending ArrayInitLoopExpr.
|
||||
static ProgramStateRef setPendingInitLoop(ProgramStateRef State,
|
||||
const CXXConstructExpr *E,
|
||||
const LocationContext *LCtx,
|
||||
unsigned Idx);
|
||||
const StackFrame *SF, unsigned Idx);
|
||||
|
||||
static ProgramStateRef removePendingInitLoop(ProgramStateRef State,
|
||||
const CXXConstructExpr *E,
|
||||
const LocationContext *LCtx);
|
||||
const StackFrame *SF);
|
||||
|
||||
static ProgramStateRef
|
||||
removeStateTraitsUsedForArrayEvaluation(ProgramStateRef State,
|
||||
const CXXConstructExpr *E,
|
||||
const LocationContext *LCtx);
|
||||
static ProgramStateRef removeStateTraitsUsedForArrayEvaluation(
|
||||
ProgramStateRef State, const CXXConstructExpr *E, const StackFrame *SF);
|
||||
|
||||
/// Store the location of a C++ object corresponding to a statement
|
||||
/// until the statement is actually encountered. For example, if a DeclStmt
|
||||
|
|
@ -1037,42 +1023,42 @@ private:
|
|||
static ProgramStateRef
|
||||
addObjectUnderConstruction(ProgramStateRef State,
|
||||
const ConstructionContextItem &Item,
|
||||
const LocationContext *LC, SVal V);
|
||||
const StackFrame *SF, SVal V);
|
||||
|
||||
/// Mark the object as fully constructed, cleaning up the state trait
|
||||
/// that tracks objects under construction.
|
||||
static ProgramStateRef
|
||||
finishObjectConstruction(ProgramStateRef State,
|
||||
const ConstructionContextItem &Item,
|
||||
const LocationContext *LC);
|
||||
const StackFrame *SF);
|
||||
|
||||
/// If the given expression corresponds to a temporary that was used for
|
||||
/// passing into an elidable copy/move constructor and that constructor
|
||||
/// was actually elided, track that we also need to elide the destructor.
|
||||
static ProgramStateRef elideDestructor(ProgramStateRef State,
|
||||
const CXXBindTemporaryExpr *BTE,
|
||||
const LocationContext *LC);
|
||||
const StackFrame *SF);
|
||||
|
||||
/// Stop tracking the destructor that corresponds to an elided constructor.
|
||||
static ProgramStateRef
|
||||
cleanupElidedDestructor(ProgramStateRef State,
|
||||
const CXXBindTemporaryExpr *BTE,
|
||||
const LocationContext *LC);
|
||||
const StackFrame *SF);
|
||||
|
||||
/// Returns true if the given expression corresponds to a temporary that
|
||||
/// was constructed for passing into an elidable copy/move constructor
|
||||
/// and that constructor was actually elided.
|
||||
static bool isDestructorElided(ProgramStateRef State,
|
||||
const CXXBindTemporaryExpr *BTE,
|
||||
const LocationContext *LC);
|
||||
const StackFrame *SF);
|
||||
|
||||
/// Check if all objects under construction have been fully constructed
|
||||
/// for the given context range (including FromLC, not including ToLC).
|
||||
/// for the given context range (including FromSF, not including ToSF).
|
||||
/// This is useful for assertions. Also checks if elided destructors
|
||||
/// were cleaned up.
|
||||
static bool areAllObjectsFullyConstructed(ProgramStateRef State,
|
||||
const LocationContext *FromLC,
|
||||
const LocationContext *ToLC);
|
||||
const StackFrame *FromSF,
|
||||
const StackFrame *ToSF);
|
||||
};
|
||||
|
||||
/// Traits for storing the call processing policy inside GDM.
|
||||
|
|
|
|||
|
|
@ -26,8 +26,7 @@ namespace ento {
|
|||
/// Widen the loop by invalidating anything that might be modified
|
||||
/// by the loop body in any iteration.
|
||||
ProgramStateRef getWidenedLoopState(ProgramStateRef PrevState,
|
||||
const LocationContext *LCtx,
|
||||
unsigned BlockCount,
|
||||
const StackFrame *SF, unsigned BlockCount,
|
||||
ConstCFGElementRef Elem);
|
||||
|
||||
} // end namespace ento
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@ namespace clang {
|
|||
class AnalysisDeclContext;
|
||||
class CXXRecordDecl;
|
||||
class Decl;
|
||||
class LocationContext;
|
||||
class StackFrame;
|
||||
|
||||
namespace ento {
|
||||
|
|
@ -707,26 +706,25 @@ class BlockDataRegion : public TypedRegion {
|
|||
friend class MemRegionManager;
|
||||
|
||||
const BlockCodeRegion *BC;
|
||||
const LocationContext *LC; // Can be null
|
||||
const StackFrame *SF;
|
||||
unsigned BlockCount;
|
||||
void *ReferencedVars = nullptr;
|
||||
void *OriginalVars = nullptr;
|
||||
|
||||
BlockDataRegion(const BlockCodeRegion *bc, const LocationContext *lc,
|
||||
BlockDataRegion(const BlockCodeRegion *bc, const StackFrame *SF,
|
||||
unsigned count, const MemSpaceRegion *sreg)
|
||||
: TypedRegion(sreg, BlockDataRegionKind), BC(bc), LC(lc),
|
||||
: TypedRegion(sreg, BlockDataRegionKind), BC(bc), SF(SF),
|
||||
BlockCount(count) {
|
||||
assert(bc);
|
||||
assert(bc->getDecl());
|
||||
assert(lc);
|
||||
assert(SF);
|
||||
assert(isa<GlobalImmutableSpaceRegion>(sreg) ||
|
||||
isa<StackLocalsSpaceRegion>(sreg) ||
|
||||
isa<UnknownSpaceRegion>(sreg));
|
||||
}
|
||||
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID&, const BlockCodeRegion *,
|
||||
const LocationContext *, unsigned,
|
||||
const MemRegion *);
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID &, const BlockCodeRegion *,
|
||||
const StackFrame *, unsigned, const MemRegion *);
|
||||
|
||||
public:
|
||||
LLVM_ATTRIBUTE_RETURNS_NONNULL
|
||||
|
|
@ -1496,18 +1494,17 @@ public:
|
|||
|
||||
/// getAllocaRegion - Retrieve a region associated with a call to alloca().
|
||||
const AllocaRegion *getAllocaRegion(const Expr *Ex, unsigned Cnt,
|
||||
const LocationContext *LC);
|
||||
const StackFrame *SF);
|
||||
|
||||
/// getCompoundLiteralRegion - Retrieve the region associated with a
|
||||
/// given CompoundLiteral.
|
||||
const CompoundLiteralRegion*
|
||||
getCompoundLiteralRegion(const CompoundLiteralExpr *CL,
|
||||
const LocationContext *LC);
|
||||
const CompoundLiteralRegion *
|
||||
getCompoundLiteralRegion(const CompoundLiteralExpr *CL, const StackFrame *SF);
|
||||
|
||||
/// getCXXThisRegion - Retrieve the [artificial] region associated with the
|
||||
/// parameter 'this'.
|
||||
const CXXThisRegion *getCXXThisRegion(QualType thisPointerTy,
|
||||
const LocationContext *LC);
|
||||
const StackFrame *SF);
|
||||
|
||||
/// Retrieve or create a "symbolic" memory region.
|
||||
/// If no memory space is specified, `UnknownSpaceRegion` will be used.
|
||||
|
|
@ -1522,19 +1519,18 @@ public:
|
|||
const ObjCStringRegion *getObjCStringRegion(const ObjCStringLiteral *Str);
|
||||
|
||||
/// getVarRegion - Retrieve or create the memory region associated with
|
||||
/// a specified VarDecl and LocationContext.
|
||||
const VarRegion *getVarRegion(const VarDecl *VD, const LocationContext *LC);
|
||||
/// a specified VarDecl and StackFrame.
|
||||
const VarRegion *getVarRegion(const VarDecl *VD, const StackFrame *SF);
|
||||
|
||||
/// getVarRegion - Retrieve or create the memory region associated with
|
||||
/// a specified VarDecl and LocationContext.
|
||||
/// a specified VarDecl and StackFrame.
|
||||
const NonParamVarRegion *getNonParamVarRegion(const VarDecl *VD,
|
||||
const MemRegion *superR);
|
||||
|
||||
/// getParamVarRegion - Retrieve or create the memory region
|
||||
/// associated with a specified CallExpr, Index and LocationContext.
|
||||
/// associated with a specified CallExpr, Index and StackFrame.
|
||||
const ParamVarRegion *getParamVarRegion(const Expr *OriginExpr,
|
||||
unsigned Index,
|
||||
const LocationContext *LC);
|
||||
unsigned Index, const StackFrame *SF);
|
||||
|
||||
/// getElementRegion - Retrieve the memory region associated with the
|
||||
/// associated element type, index, and super region.
|
||||
|
|
@ -1568,18 +1564,18 @@ public:
|
|||
const SubRegion* superRegion);
|
||||
|
||||
const CXXTempObjectRegion *getCXXTempObjectRegion(Expr const *Ex,
|
||||
LocationContext const *LC);
|
||||
StackFrame const *SF);
|
||||
|
||||
/// Create a CXXLifetimeExtendedObjectRegion for temporaries which are
|
||||
/// lifetime-extended by local references.
|
||||
const CXXLifetimeExtendedObjectRegion *
|
||||
getCXXLifetimeExtendedObjectRegion(Expr const *Ex, ValueDecl const *VD,
|
||||
LocationContext const *LC);
|
||||
StackFrame const *SF);
|
||||
|
||||
/// Create a CXXLifetimeExtendedObjectRegion for temporaries which are
|
||||
/// lifetime-extended by *static* references.
|
||||
/// This differs from \ref getCXXLifetimeExtendedObjectRegion(Expr const *,
|
||||
/// ValueDecl const *, LocationContext const *) in the super-region used.
|
||||
/// ValueDecl const *, StackFrame const *) in the super-region used.
|
||||
const CXXLifetimeExtendedObjectRegion *
|
||||
getCXXStaticLifetimeExtendedObjectRegion(const Expr *Ex, ValueDecl const *VD);
|
||||
|
||||
|
|
@ -1614,11 +1610,10 @@ public:
|
|||
AnalysisDeclContext *AC);
|
||||
|
||||
/// getBlockDataRegion - Get the memory region associated with an instance
|
||||
/// of a block. Unlike many other MemRegions, the LocationContext*
|
||||
/// argument is allowed to be NULL for cases where we have no known
|
||||
/// context.
|
||||
/// of a block. Unlike many other MemRegions, the StackFrame * argument
|
||||
/// is allowed to be NULL for cases where we have no known stack frame.
|
||||
const BlockDataRegion *getBlockDataRegion(const BlockCodeRegion *bc,
|
||||
const LocationContext *lc,
|
||||
const StackFrame *SF,
|
||||
unsigned blockCount);
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -272,7 +272,7 @@ public:
|
|||
|
||||
/// Utility method for getting regions.
|
||||
LLVM_ATTRIBUTE_RETURNS_NONNULL
|
||||
const VarRegion* getRegion(const VarDecl *D, const LocationContext *LC) const;
|
||||
const VarRegion *getRegion(const VarDecl *D, const StackFrame *SF) const;
|
||||
|
||||
//==---------------------------------------------------------------------==//
|
||||
// Binding and retrieving values to/from the environment and symbolic store.
|
||||
|
|
@ -280,16 +280,15 @@ public:
|
|||
|
||||
/// Create a new state by binding the value \p V to the expression \p E in
|
||||
/// the state's environment.
|
||||
[[nodiscard]] ProgramStateRef BindExpr(const Expr *E,
|
||||
const LocationContext *LCtx, SVal V,
|
||||
bool Invalidate = true) const;
|
||||
[[nodiscard]] ProgramStateRef BindExpr(const Expr *E, const StackFrame *SF,
|
||||
SVal V, bool Invalidate = true) const;
|
||||
|
||||
[[nodiscard]] ProgramStateRef bindLoc(Loc location, SVal V,
|
||||
const LocationContext *LCtx,
|
||||
const StackFrame *SF,
|
||||
bool notifyChanges = true) const;
|
||||
|
||||
[[nodiscard]] ProgramStateRef bindLoc(SVal location, SVal V,
|
||||
const LocationContext *LCtx) const;
|
||||
const StackFrame *SF) const;
|
||||
|
||||
/// Initializes the region of memory represented by \p loc with an initial
|
||||
/// value. Once initialized, all values loaded from any sub-regions of that
|
||||
|
|
@ -297,13 +296,13 @@ public:
|
|||
/// This method should not be used on regions that are already initialized.
|
||||
/// If you need to indicate that memory contents have suddenly become unknown
|
||||
/// within a certain region of memory, consider invalidateRegions().
|
||||
[[nodiscard]] ProgramStateRef
|
||||
bindDefaultInitial(SVal loc, SVal V, const LocationContext *LCtx) const;
|
||||
[[nodiscard]] ProgramStateRef bindDefaultInitial(SVal loc, SVal V,
|
||||
const StackFrame *SF) const;
|
||||
|
||||
/// Performs C++ zero-initialization procedure on the region of memory
|
||||
/// represented by \p loc.
|
||||
[[nodiscard]] ProgramStateRef
|
||||
bindDefaultZero(SVal loc, const LocationContext *LCtx) const;
|
||||
[[nodiscard]] ProgramStateRef bindDefaultZero(SVal loc,
|
||||
const StackFrame *SF) const;
|
||||
|
||||
[[nodiscard]] ProgramStateRef killBinding(Loc LV) const;
|
||||
|
||||
|
|
@ -328,17 +327,15 @@ public:
|
|||
/// the call and should be considered directly invalidated.
|
||||
/// \param ITraits information about special handling for particular regions
|
||||
/// or symbols.
|
||||
[[nodiscard]] ProgramStateRef
|
||||
invalidateRegions(ArrayRef<const MemRegion *> Regions,
|
||||
ConstCFGElementRef Elem, unsigned BlockCount,
|
||||
const LocationContext *LCtx, bool CausesPointerEscape,
|
||||
InvalidatedSymbols *IS = nullptr,
|
||||
const CallEvent *Call = nullptr,
|
||||
RegionAndSymbolInvalidationTraits *ITraits = nullptr) const;
|
||||
[[nodiscard]] ProgramStateRef invalidateRegions(
|
||||
ArrayRef<const MemRegion *> Regions, ConstCFGElementRef Elem,
|
||||
unsigned BlockCount, const StackFrame *SF, bool CausesPointerEscape,
|
||||
InvalidatedSymbols *IS = nullptr, const CallEvent *Call = nullptr,
|
||||
RegionAndSymbolInvalidationTraits *ITraits = nullptr) const;
|
||||
|
||||
[[nodiscard]] ProgramStateRef
|
||||
invalidateRegions(ArrayRef<SVal> Values, ConstCFGElementRef Elem,
|
||||
unsigned BlockCount, const LocationContext *LCtx,
|
||||
unsigned BlockCount, const StackFrame *SF,
|
||||
bool CausesPointerEscape, InvalidatedSymbols *IS = nullptr,
|
||||
const CallEvent *Call = nullptr,
|
||||
RegionAndSymbolInvalidationTraits *ITraits = nullptr) const;
|
||||
|
|
@ -349,7 +346,7 @@ public:
|
|||
enterStackFrame(const CallEvent &Call, const StackFrame *CalleeSF) const;
|
||||
|
||||
/// Return the value of 'self' if available in the given context.
|
||||
SVal getSelfSVal(const LocationContext *LC) const;
|
||||
SVal getSelfSVal(const StackFrame *SF) const;
|
||||
|
||||
/// Get the lvalue for a base class object reference.
|
||||
Loc getLValue(const CXXBaseSpecifier &BaseSpec, const SubRegion *Super) const;
|
||||
|
|
@ -359,10 +356,9 @@ public:
|
|||
bool IsVirtual) const;
|
||||
|
||||
/// Get the lvalue for a variable reference.
|
||||
Loc getLValue(const VarDecl *D, const LocationContext *LC) const;
|
||||
Loc getLValue(const VarDecl *D, const StackFrame *SF) const;
|
||||
|
||||
Loc getLValue(const CompoundLiteralExpr *literal,
|
||||
const LocationContext *LC) const;
|
||||
Loc getLValue(const CompoundLiteralExpr *literal, const StackFrame *SF) const;
|
||||
|
||||
/// Get the lvalue for an ivar reference.
|
||||
SVal getLValue(const ObjCIvarDecl *decl, SVal base) const;
|
||||
|
|
@ -377,9 +373,9 @@ public:
|
|||
SVal getLValue(QualType ElementType, SVal Idx, SVal Base) const;
|
||||
|
||||
/// Returns the SVal bound to the expression \p E in the state's environment.
|
||||
SVal getSVal(const Expr *E, const LocationContext *LCtx) const;
|
||||
SVal getSVal(const Expr *E, const StackFrame *SF) const;
|
||||
|
||||
SVal getSValAsScalarOrLoc(const Expr *E, const LocationContext *LCtx) const;
|
||||
SVal getSValAsScalarOrLoc(const Expr *E, const StackFrame *SF) const;
|
||||
|
||||
/// Return the value bound to the specified location.
|
||||
/// Returns UnknownVal() if none found.
|
||||
|
|
@ -477,11 +473,11 @@ public:
|
|||
}
|
||||
|
||||
// Pretty-printing.
|
||||
void printJson(raw_ostream &Out, const LocationContext *LCtx = nullptr,
|
||||
void printJson(raw_ostream &Out, const StackFrame *SF = nullptr,
|
||||
const char *NL = "\n", unsigned int Space = 0,
|
||||
bool IsDot = false) const;
|
||||
|
||||
void printDOT(raw_ostream &Out, const LocationContext *LCtx = nullptr,
|
||||
void printDOT(raw_ostream &Out, const StackFrame *SF = nullptr,
|
||||
unsigned int Space = 0) const;
|
||||
|
||||
void dump() const;
|
||||
|
|
@ -540,7 +536,7 @@ public:
|
|||
|
||||
~ProgramStateManager();
|
||||
|
||||
ProgramStateRef getInitialState(const LocationContext *InitLoc);
|
||||
ProgramStateRef getInitialState(const StackFrame *InitSF);
|
||||
|
||||
ASTContext &getContext() { return svalBuilder->getContext(); }
|
||||
const ASTContext &getContext() const { return svalBuilder->getContext(); }
|
||||
|
|
@ -698,10 +694,9 @@ inline ConstraintManager &ProgramState::getConstraintManager() const {
|
|||
return stateMgr->getConstraintManager();
|
||||
}
|
||||
|
||||
inline const VarRegion* ProgramState::getRegion(const VarDecl *D,
|
||||
const LocationContext *LC) const
|
||||
{
|
||||
return getStateManager().getRegionManager().getVarRegion(D, LC);
|
||||
inline const VarRegion *ProgramState::getRegion(const VarDecl *D,
|
||||
const StackFrame *SF) const {
|
||||
return getStateManager().getRegionManager().getVarRegion(D, SF);
|
||||
}
|
||||
|
||||
inline ProgramStateRef ProgramState::assume(DefinedOrUnknownSVal Cond,
|
||||
|
|
@ -747,9 +742,10 @@ ProgramState::assumeInclusiveRange(DefinedOrUnknownSVal Val,
|
|||
this, Val.castAs<NonLoc>(), From, To);
|
||||
}
|
||||
|
||||
inline ProgramStateRef ProgramState::bindLoc(SVal LV, SVal V, const LocationContext *LCtx) const {
|
||||
inline ProgramStateRef ProgramState::bindLoc(SVal LV, SVal V,
|
||||
const StackFrame *SF) const {
|
||||
if (std::optional<Loc> L = LV.getAs<Loc>())
|
||||
return bindLoc(*L, V, LCtx);
|
||||
return bindLoc(*L, V, SF);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -770,13 +766,13 @@ inline Loc ProgramState::getLValue(const CXXRecordDecl *BaseClass,
|
|||
}
|
||||
|
||||
inline Loc ProgramState::getLValue(const VarDecl *VD,
|
||||
const LocationContext *LC) const {
|
||||
return getStateManager().StoreMgr->getLValueVar(VD, LC);
|
||||
const StackFrame *SF) const {
|
||||
return getStateManager().StoreMgr->getLValueVar(VD, SF);
|
||||
}
|
||||
|
||||
inline Loc ProgramState::getLValue(const CompoundLiteralExpr *literal,
|
||||
const LocationContext *LC) const {
|
||||
return getStateManager().StoreMgr->getLValueCompoundLiteral(literal, LC);
|
||||
const StackFrame *SF) const {
|
||||
return getStateManager().StoreMgr->getLValueCompoundLiteral(literal, SF);
|
||||
}
|
||||
|
||||
inline SVal ProgramState::getLValue(const ObjCIvarDecl *D, SVal Base) const {
|
||||
|
|
@ -789,17 +785,15 @@ inline SVal ProgramState::getLValue(QualType ElementType, SVal Idx, SVal Base) c
|
|||
return UnknownVal();
|
||||
}
|
||||
|
||||
inline SVal ProgramState::getSVal(const Expr *E,
|
||||
const LocationContext *LCtx) const {
|
||||
return Env.getSVal(EnvironmentEntry(E, LCtx), *getStateManager().svalBuilder);
|
||||
inline SVal ProgramState::getSVal(const Expr *E, const StackFrame *SF) const {
|
||||
return Env.getSVal(EnvironmentEntry(E, SF), *getStateManager().svalBuilder);
|
||||
}
|
||||
|
||||
inline SVal
|
||||
ProgramState::getSValAsScalarOrLoc(const Expr *E,
|
||||
const LocationContext *LCtx) const {
|
||||
inline SVal ProgramState::getSValAsScalarOrLoc(const Expr *E,
|
||||
const StackFrame *SF) const {
|
||||
QualType T = E->getType();
|
||||
if (E->isGLValue() || Loc::isLocType(T) || T->isIntegralOrEnumerationType())
|
||||
return getSVal(E, LCtx);
|
||||
return getSVal(E, SF);
|
||||
return UnknownVal();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@ class CXXMethodDecl;
|
|||
class CXXRecordDecl;
|
||||
class DeclaratorDecl;
|
||||
class FunctionDecl;
|
||||
class LocationContext;
|
||||
class StackFrame;
|
||||
class Stmt;
|
||||
|
||||
|
|
@ -173,10 +172,10 @@ public:
|
|||
// Forwarding methods to SymbolManager.
|
||||
|
||||
const SymbolConjured *conjureSymbol(ConstCFGElementRef Elem,
|
||||
const LocationContext *LCtx,
|
||||
QualType type, unsigned visitCount,
|
||||
const StackFrame *SF, QualType type,
|
||||
unsigned visitCount,
|
||||
const void *symbolTag = nullptr) {
|
||||
return SymMgr.conjureSymbol(Elem, LCtx, type, visitCount, symbolTag);
|
||||
return SymMgr.conjureSymbol(Elem, SF, type, visitCount, symbolTag);
|
||||
}
|
||||
|
||||
/// Construct an SVal representing '0' for the specified type.
|
||||
|
|
@ -193,15 +192,14 @@ public:
|
|||
/// conjured symbols should be used sparingly.
|
||||
DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag,
|
||||
ConstCFGElementRef elem,
|
||||
const LocationContext *LCtx,
|
||||
unsigned count);
|
||||
const StackFrame *SF, unsigned count);
|
||||
DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag,
|
||||
ConstCFGElementRef elem,
|
||||
const LocationContext *LCtx,
|
||||
QualType type, unsigned count);
|
||||
const StackFrame *SF, QualType type,
|
||||
unsigned count);
|
||||
DefinedOrUnknownSVal conjureSymbolVal(ConstCFGElementRef elem,
|
||||
const LocationContext *LCtx,
|
||||
QualType type, unsigned visitCount);
|
||||
const StackFrame *SF, QualType type,
|
||||
unsigned visitCount);
|
||||
DefinedOrUnknownSVal conjureSymbolVal(const CallEvent &call, QualType type,
|
||||
unsigned visitCount,
|
||||
const void *symbolTag = nullptr);
|
||||
|
|
@ -211,25 +209,23 @@ public:
|
|||
|
||||
/// Conjure a symbol representing heap allocated memory region.
|
||||
DefinedSVal getConjuredHeapSymbolVal(ConstCFGElementRef elem,
|
||||
const LocationContext *LCtx,
|
||||
QualType type, unsigned Count);
|
||||
const StackFrame *SF, QualType type,
|
||||
unsigned Count);
|
||||
|
||||
/// Create an SVal representing the result of an alloca()-like call, that is,
|
||||
/// an AllocaRegion on the stack.
|
||||
///
|
||||
/// After calling this function, it's a good idea to set the extent of the
|
||||
/// returned AllocaRegion.
|
||||
loc::MemRegionVal getAllocaRegionVal(const Expr *E,
|
||||
const LocationContext *LCtx,
|
||||
loc::MemRegionVal getAllocaRegionVal(const Expr *E, const StackFrame *SF,
|
||||
unsigned Count);
|
||||
|
||||
DefinedOrUnknownSVal getDerivedRegionValueSymbolVal(
|
||||
SymbolRef parentSymbol, const TypedValueRegion *region);
|
||||
|
||||
DefinedSVal getMetadataSymbolVal(const void *symbolTag,
|
||||
const MemRegion *region,
|
||||
const Expr *expr, QualType type,
|
||||
const LocationContext *LCtx,
|
||||
const MemRegion *region, const Expr *expr,
|
||||
QualType type, const StackFrame *SF,
|
||||
unsigned count);
|
||||
|
||||
DefinedSVal getMemberPointer(const NamedDecl *ND);
|
||||
|
|
@ -237,8 +233,7 @@ public:
|
|||
DefinedSVal getFunctionPointer(const FunctionDecl *func);
|
||||
|
||||
DefinedSVal getBlockPointer(const BlockDecl *block, CanQualType locTy,
|
||||
const LocationContext *locContext,
|
||||
unsigned blockCount);
|
||||
const StackFrame *SF, unsigned blockCount);
|
||||
|
||||
/// Returns the value of \p E, if it can be determined in a non-path-sensitive
|
||||
/// manner.
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ class CompoundLiteralExpr;
|
|||
class CXXBasePath;
|
||||
class Decl;
|
||||
class Expr;
|
||||
class LocationContext;
|
||||
class ObjCIvarDecl;
|
||||
class StackFrame;
|
||||
|
||||
|
|
@ -132,7 +131,7 @@ public:
|
|||
|
||||
/// getInitialStore - Returns the initial "empty" store representing the
|
||||
/// value bindings upon entry to an analyzed function.
|
||||
virtual StoreRef getInitialStore(const LocationContext *InitLoc) = 0;
|
||||
virtual StoreRef getInitialStore(const StackFrame *InitSF) = 0;
|
||||
|
||||
/// getRegionManager - Returns the internal RegionManager object that is
|
||||
/// used to query and manipulate MemRegion objects.
|
||||
|
|
@ -140,13 +139,13 @@ public:
|
|||
|
||||
SValBuilder& getSValBuilder() { return svalBuilder; }
|
||||
|
||||
virtual Loc getLValueVar(const VarDecl *VD, const LocationContext *LC) {
|
||||
return svalBuilder.makeLoc(MRMgr.getVarRegion(VD, LC));
|
||||
virtual Loc getLValueVar(const VarDecl *VD, const StackFrame *SF) {
|
||||
return svalBuilder.makeLoc(MRMgr.getVarRegion(VD, SF));
|
||||
}
|
||||
|
||||
Loc getLValueCompoundLiteral(const CompoundLiteralExpr *CL,
|
||||
const LocationContext *LC) {
|
||||
return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC));
|
||||
const StackFrame *SF) {
|
||||
return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, SF));
|
||||
}
|
||||
|
||||
virtual SVal getLValueIvar(const ObjCIvarDecl *decl, SVal base);
|
||||
|
|
@ -242,7 +241,7 @@ public:
|
|||
/// information will not be used.
|
||||
virtual StoreRef invalidateRegions(
|
||||
Store store, ArrayRef<SVal> Values, ConstCFGElementRef Elem,
|
||||
unsigned Count, const LocationContext *LCtx, const CallEvent *Call,
|
||||
unsigned Count, const StackFrame *SF, const CallEvent *Call,
|
||||
InvalidatedSymbols &IS, RegionAndSymbolInvalidationTraits &ITraits,
|
||||
InvalidatedRegions *TopLevelRegions, InvalidatedRegions *Invalidated) = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -83,16 +83,15 @@ class SymbolConjured : public SymbolData {
|
|||
ConstCFGElementRef Elem;
|
||||
QualType T;
|
||||
unsigned Count;
|
||||
const LocationContext *LCtx;
|
||||
const StackFrame *SF;
|
||||
const void *SymbolTag;
|
||||
|
||||
friend class SymExprAllocator;
|
||||
SymbolConjured(SymbolID sym, ConstCFGElementRef elem,
|
||||
const LocationContext *lctx, QualType t, unsigned count,
|
||||
const void *symbolTag)
|
||||
: SymbolData(ClassKind, sym), Elem(elem), T(t), Count(count), LCtx(lctx),
|
||||
SymbolConjured(SymbolID sym, ConstCFGElementRef elem, const StackFrame *SF,
|
||||
QualType t, unsigned count, const void *symbolTag)
|
||||
: SymbolData(ClassKind, sym), Elem(elem), T(t), Count(count), SF(SF),
|
||||
SymbolTag(symbolTag) {
|
||||
assert(lctx);
|
||||
assert(SF);
|
||||
assert(isValidTypeForSymbol(t));
|
||||
}
|
||||
|
||||
|
|
@ -113,18 +112,18 @@ public:
|
|||
void dumpToStream(raw_ostream &os) const override;
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &profile, ConstCFGElementRef Elem,
|
||||
const LocationContext *LCtx, QualType T, unsigned Count,
|
||||
const StackFrame *SF, QualType T, unsigned Count,
|
||||
const void *SymbolTag) {
|
||||
profile.AddInteger((unsigned)ClassKind);
|
||||
profile.Add(Elem);
|
||||
profile.AddPointer(LCtx);
|
||||
profile.AddPointer(SF);
|
||||
profile.Add(T);
|
||||
profile.AddInteger(Count);
|
||||
profile.AddPointer(SymbolTag);
|
||||
}
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID& profile) override {
|
||||
Profile(profile, Elem, LCtx, T, Count, SymbolTag);
|
||||
Profile(profile, Elem, SF, T, Count, SymbolTag);
|
||||
}
|
||||
|
||||
// Implement isa<T> support.
|
||||
|
|
@ -222,7 +221,7 @@ class SymbolMetadata : public SymbolData {
|
|||
const MemRegion* R;
|
||||
const Stmt *S;
|
||||
QualType T;
|
||||
const LocationContext *LCtx;
|
||||
const StackFrame *SF;
|
||||
/// Count can be used to differentiate regions corresponding to
|
||||
/// different loop iterations, thus, making the symbol path-dependent.
|
||||
unsigned Count;
|
||||
|
|
@ -230,13 +229,13 @@ class SymbolMetadata : public SymbolData {
|
|||
|
||||
friend class SymExprAllocator;
|
||||
SymbolMetadata(SymbolID sym, const MemRegion *r, const Stmt *s, QualType t,
|
||||
const LocationContext *LCtx, unsigned count, const void *tag)
|
||||
: SymbolData(ClassKind, sym), R(r), S(s), T(t), LCtx(LCtx), Count(count),
|
||||
const StackFrame *SF, unsigned count, const void *tag)
|
||||
: SymbolData(ClassKind, sym), R(r), S(s), T(t), SF(SF), Count(count),
|
||||
Tag(tag) {
|
||||
assert(r);
|
||||
assert(s);
|
||||
assert(isValidTypeForSymbol(t));
|
||||
assert(LCtx);
|
||||
assert(SF);
|
||||
assert(tag);
|
||||
}
|
||||
|
||||
|
|
@ -248,7 +247,7 @@ class SymbolMetadata : public SymbolData {
|
|||
const Stmt *getStmt() const { return S; }
|
||||
|
||||
LLVM_ATTRIBUTE_RETURNS_NONNULL
|
||||
const LocationContext *getLocationContext() const { return LCtx; }
|
||||
const StackFrame *getStackFrame() const { return SF; }
|
||||
|
||||
unsigned getCount() const { return Count; }
|
||||
|
||||
|
|
@ -262,19 +261,19 @@ class SymbolMetadata : public SymbolData {
|
|||
void dumpToStream(raw_ostream &os) const override;
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &profile, const MemRegion *R,
|
||||
const Stmt *S, QualType T, const LocationContext *LCtx,
|
||||
const Stmt *S, QualType T, const StackFrame *SF,
|
||||
unsigned Count, const void *Tag) {
|
||||
profile.AddInteger((unsigned)ClassKind);
|
||||
profile.AddPointer(R);
|
||||
profile.AddPointer(S);
|
||||
profile.Add(T);
|
||||
profile.AddPointer(LCtx);
|
||||
profile.AddPointer(SF);
|
||||
profile.AddInteger(Count);
|
||||
profile.AddPointer(Tag);
|
||||
}
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID& profile) override {
|
||||
Profile(profile, R, S, T, LCtx, Count, Tag);
|
||||
Profile(profile, R, S, T, SF, Count, Tag);
|
||||
}
|
||||
|
||||
// Implement isa<T> support.
|
||||
|
|
@ -535,11 +534,11 @@ public:
|
|||
const SymExprT *acquire(Args &&...args);
|
||||
|
||||
const SymbolConjured *conjureSymbol(ConstCFGElementRef Elem,
|
||||
const LocationContext *LCtx, QualType T,
|
||||
const StackFrame *SF, QualType T,
|
||||
unsigned VisitCount,
|
||||
const void *SymbolTag = nullptr) {
|
||||
|
||||
return acquire<SymbolConjured>(Elem, LCtx, T, VisitCount, SymbolTag);
|
||||
return acquire<SymbolConjured>(Elem, SF, T, VisitCount, SymbolTag);
|
||||
}
|
||||
|
||||
QualType getType(const SymExpr *SE) const {
|
||||
|
|
@ -586,22 +585,21 @@ class SymbolReaper {
|
|||
|
||||
public:
|
||||
/// Construct a reaper object, which removes everything which is not
|
||||
/// live before we execute statement s in the given location context.
|
||||
/// live before we execute statements in the given stack frame.
|
||||
///
|
||||
/// If the statement is NULL, everything is this and parent contexts is
|
||||
/// If the statement is NULL, everything in this and parent stack frames are
|
||||
/// considered live.
|
||||
/// If the stack frame context is NULL, everything on stack is considered
|
||||
/// dead.
|
||||
/// If the stack frame is NULL, everything on stack is considered dead.
|
||||
SymbolReaper(const StackFrame *SF, const Stmt *s, SymbolManager &symmgr,
|
||||
StoreManager &storeMgr)
|
||||
: SF(SF), Loc(s), SymMgr(symmgr), reapedStore(nullptr, storeMgr) {}
|
||||
|
||||
/// It might return null.
|
||||
const LocationContext *getLocationContext() const { return SF; }
|
||||
const StackFrame *getStackFrame() const { return SF; }
|
||||
|
||||
bool isLive(SymbolRef sym);
|
||||
bool isLiveRegion(const MemRegion *region);
|
||||
bool isLive(const Expr *ExprVal, const LocationContext *LCtx) const;
|
||||
bool isLive(const Expr *ExprVal, const StackFrame *SF) const;
|
||||
bool isLive(const VarRegion *VR, bool includeStoreBindings = false) const;
|
||||
|
||||
/// Unconditionally marks a symbol as live.
|
||||
|
|
|
|||
|
|
@ -310,11 +310,12 @@ AnalysisDeclContext *AnalysisDeclContextManager::getContext(const Decl *D) {
|
|||
|
||||
BodyFarm &AnalysisDeclContextManager::getBodyFarm() { return FunctionBodyFarm; }
|
||||
|
||||
const StackFrame *AnalysisDeclContext::getStackFrame(
|
||||
const LocationContext *ParentLC, const void *Data, const Expr *E,
|
||||
const CFGBlock *Blk, unsigned BlockCount, unsigned Index) {
|
||||
return getLocationContextManager().getStackFrame(this, ParentLC, Data, E, Blk,
|
||||
BlockCount, Index);
|
||||
const StackFrame *
|
||||
AnalysisDeclContext::getStackFrame(const StackFrame *ParentSF, const void *Data,
|
||||
const Expr *E, const CFGBlock *Blk,
|
||||
unsigned BlockCount, unsigned Index) {
|
||||
return getStackFrameManager().getStackFrame(this, ParentSF, Data, E, Blk,
|
||||
BlockCount, Index);
|
||||
}
|
||||
|
||||
bool AnalysisDeclContext::isInStdNamespace(const Decl *D) {
|
||||
|
|
@ -385,78 +386,51 @@ std::string AnalysisDeclContext::getFunctionName(const Decl *D) {
|
|||
return Str;
|
||||
}
|
||||
|
||||
LocationContextManager &AnalysisDeclContext::getLocationContextManager() {
|
||||
assert(
|
||||
ADCMgr &&
|
||||
"Cannot create LocationContexts without an AnalysisDeclContextManager!");
|
||||
return ADCMgr->getLocationContextManager();
|
||||
StackFrameManager &AnalysisDeclContext::getStackFrameManager() {
|
||||
assert(ADCMgr &&
|
||||
"Cannot create StackFrames without an AnalysisDeclContextManager!");
|
||||
return ADCMgr->getStackFrameManager();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// FoldingSet profiling.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void LocationContext::ProfileCommon(llvm::FoldingSetNodeID &ID,
|
||||
ContextKind ck,
|
||||
AnalysisDeclContext *ctx,
|
||||
const LocationContext *parent,
|
||||
const void *data) {
|
||||
ID.AddInteger(ck);
|
||||
ID.AddPointer(ctx);
|
||||
ID.AddPointer(parent);
|
||||
ID.AddPointer(data);
|
||||
}
|
||||
|
||||
void StackFrame::Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, getAnalysisDeclContext(), getParent(), Data, CallSite, Block,
|
||||
BlockCount, Index);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// LocationContext creation.
|
||||
// StackFrame creation.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
const StackFrame *LocationContextManager::getStackFrame(
|
||||
AnalysisDeclContext *Ctx, const LocationContext *Parent, const void *Data,
|
||||
const Expr *E, const CFGBlock *Blk, unsigned BlockCount, unsigned StmtIdx) {
|
||||
const StackFrame *StackFrameManager::getStackFrame(
|
||||
AnalysisDeclContext *Ctx, const StackFrame *Parent, const void *Data,
|
||||
const Expr *E, const CFGBlock *B, unsigned BlockCount, unsigned StmtIdx) {
|
||||
llvm::FoldingSetNodeID ID;
|
||||
StackFrame::Profile(ID, Ctx, Parent, Data, E, Blk, BlockCount, StmtIdx);
|
||||
StackFrame::Profile(ID, Ctx, Parent, Data, E, B, BlockCount, StmtIdx);
|
||||
void *InsertPos;
|
||||
auto *L =
|
||||
cast_or_null<StackFrame>(Contexts.FindNodeOrInsertPos(ID, InsertPos));
|
||||
if (!L) {
|
||||
L = new StackFrame(Ctx, Parent, Data, E, Blk, BlockCount, StmtIdx, ++NewID);
|
||||
Contexts.InsertNode(L, InsertPos);
|
||||
StackFrame *SF = Frames.FindNodeOrInsertPos(ID, InsertPos);
|
||||
if (!SF) {
|
||||
SF = new StackFrame(Ctx, Parent, Data, E, B, BlockCount, StmtIdx, ++NewID);
|
||||
Frames.InsertNode(SF, InsertPos);
|
||||
}
|
||||
return L;
|
||||
return SF;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// LocationContext methods.
|
||||
// StackFrame methods.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
const StackFrame *LocationContext::getStackFrame() const {
|
||||
const LocationContext *LC = this;
|
||||
while (LC) {
|
||||
if (const auto *SF = dyn_cast<StackFrame>(LC))
|
||||
return SF;
|
||||
LC = LC->getParent();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool LocationContext::inTopFrame() const {
|
||||
return getStackFrame()->inTopFrame();
|
||||
}
|
||||
|
||||
bool LocationContext::isParentOf(const LocationContext *LC) const {
|
||||
bool StackFrame::isParentOf(const StackFrame *SF) const {
|
||||
do {
|
||||
const LocationContext *Parent = LC->getParent();
|
||||
const StackFrame *Parent = SF->getParent();
|
||||
if (Parent == this)
|
||||
return true;
|
||||
else
|
||||
LC = Parent;
|
||||
} while (LC);
|
||||
SF = Parent;
|
||||
} while (SF);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -469,7 +443,7 @@ static void printLocation(raw_ostream &Out, const SourceManager &SM,
|
|||
Loc.print(Out, SM);
|
||||
}
|
||||
|
||||
void LocationContext::dumpStack(raw_ostream &Out) const {
|
||||
void StackFrame::dumpStack(raw_ostream &Out) const {
|
||||
ASTContext &Ctx = getAnalysisDeclContext()->getASTContext();
|
||||
PrintingPolicy PP(Ctx.getLangOpts());
|
||||
PP.TerseOutput = 1;
|
||||
|
|
@ -478,29 +452,24 @@ void LocationContext::dumpStack(raw_ostream &Out) const {
|
|||
getAnalysisDeclContext()->getASTContext().getSourceManager();
|
||||
|
||||
unsigned Frame = 0;
|
||||
for (const LocationContext *LCtx = this; LCtx; LCtx = LCtx->getParent()) {
|
||||
switch (LCtx->getKind()) {
|
||||
case StackFrameKind:
|
||||
Out << "\t#" << Frame << ' ';
|
||||
++Frame;
|
||||
if (const auto *D = dyn_cast<NamedDecl>(LCtx->getDecl()))
|
||||
Out << "Calling " << AnalysisDeclContext::getFunctionName(D);
|
||||
else
|
||||
Out << "Calling anonymous code";
|
||||
if (const Expr *E = cast<StackFrame>(LCtx)->getCallSite()) {
|
||||
Out << " at line ";
|
||||
printLocation(Out, SM, E->getBeginLoc());
|
||||
}
|
||||
break;
|
||||
for (const StackFrame *SF = this; SF; SF = SF->getParent()) {
|
||||
Out << "\t#" << Frame << ' ';
|
||||
++Frame;
|
||||
if (const auto *D = dyn_cast<NamedDecl>(SF->getDecl()))
|
||||
Out << "Calling " << AnalysisDeclContext::getFunctionName(D);
|
||||
else
|
||||
Out << "Calling anonymous code";
|
||||
if (const Expr *E = SF->getCallSite()) {
|
||||
Out << " at line ";
|
||||
printLocation(Out, SM, E->getBeginLoc());
|
||||
}
|
||||
Out << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
void LocationContext::printJson(raw_ostream &Out, const char *NL,
|
||||
unsigned int Space, bool IsDot,
|
||||
std::function<void(const LocationContext *)>
|
||||
printMoreInfoPerContext) const {
|
||||
void StackFrame::printJson(
|
||||
raw_ostream &Out, const char *NL, unsigned int Space, bool IsDot,
|
||||
std::function<void(const StackFrame *)> printMoreInfoPerStackFrame) const {
|
||||
ASTContext &Ctx = getAnalysisDeclContext()->getASTContext();
|
||||
PrintingPolicy PP(Ctx.getLangOpts());
|
||||
PP.TerseOutput = 1;
|
||||
|
|
@ -509,39 +478,35 @@ void LocationContext::printJson(raw_ostream &Out, const char *NL,
|
|||
getAnalysisDeclContext()->getASTContext().getSourceManager();
|
||||
|
||||
unsigned Frame = 0;
|
||||
for (const LocationContext *LCtx = this; LCtx; LCtx = LCtx->getParent()) {
|
||||
for (const StackFrame *SF = this; SF; SF = SF->getParent()) {
|
||||
Indent(Out, Space, IsDot)
|
||||
<< "{ \"lctx_id\": " << LCtx->getID() << ", \"location_context\": \"";
|
||||
switch (LCtx->getKind()) {
|
||||
case StackFrameKind:
|
||||
Out << '#' << Frame << " Call\", \"calling\": \"";
|
||||
++Frame;
|
||||
if (const auto *D = dyn_cast<NamedDecl>(LCtx->getDecl()))
|
||||
Out << D->getQualifiedNameAsString();
|
||||
else
|
||||
Out << "anonymous code";
|
||||
<< "{ \"lctx_id\": " << SF->getID() << ", \"location_context\": \"";
|
||||
Out << '#' << Frame << " Call\", \"calling\": \"";
|
||||
++Frame;
|
||||
if (const auto *D = dyn_cast<NamedDecl>(SF->getDecl()))
|
||||
Out << D->getQualifiedNameAsString();
|
||||
else
|
||||
Out << "anonymous code";
|
||||
|
||||
Out << "\", \"location\": ";
|
||||
if (const Expr *E = cast<StackFrame>(LCtx)->getCallSite()) {
|
||||
printSourceLocationAsJson(Out, E->getBeginLoc(), SM);
|
||||
} else {
|
||||
Out << "null";
|
||||
}
|
||||
|
||||
Out << ", \"items\": ";
|
||||
break;
|
||||
Out << "\", \"location\": ";
|
||||
if (const Expr *E = SF->getCallSite()) {
|
||||
printSourceLocationAsJson(Out, E->getBeginLoc(), SM);
|
||||
} else {
|
||||
Out << "null";
|
||||
}
|
||||
|
||||
printMoreInfoPerContext(LCtx);
|
||||
Out << ", \"items\": ";
|
||||
|
||||
printMoreInfoPerStackFrame(SF);
|
||||
|
||||
Out << '}';
|
||||
if (LCtx->getParent())
|
||||
if (SF->getParent())
|
||||
Out << ',';
|
||||
Out << NL;
|
||||
}
|
||||
}
|
||||
|
||||
LLVM_DUMP_METHOD void LocationContext::dump() const { printJson(llvm::errs()); }
|
||||
LLVM_DUMP_METHOD void StackFrame::dump() const { printJson(llvm::errs()); }
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Lazily generated map to query the external variables referenced by a Block.
|
||||
|
|
@ -649,18 +614,15 @@ AnalysisDeclContext::~AnalysisDeclContext() {
|
|||
delete (ManagedAnalysisMap*) ManagedAnalyses;
|
||||
}
|
||||
|
||||
LocationContext::~LocationContext() = default;
|
||||
StackFrameManager::~StackFrameManager() { clear(); }
|
||||
|
||||
LocationContextManager::~LocationContextManager() {
|
||||
clear();
|
||||
}
|
||||
|
||||
void LocationContextManager::clear() {
|
||||
for (llvm::FoldingSet<LocationContext>::iterator I = Contexts.begin(),
|
||||
E = Contexts.end(); I != E; ) {
|
||||
LocationContext *LC = &*I;
|
||||
void StackFrameManager::clear() {
|
||||
for (llvm::FoldingSet<StackFrame>::iterator I = Frames.begin(),
|
||||
E = Frames.end();
|
||||
I != E;) {
|
||||
StackFrame *SF = &*I;
|
||||
++I;
|
||||
delete LC;
|
||||
delete SF;
|
||||
}
|
||||
Contexts.clear();
|
||||
Frames.clear();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -470,20 +470,21 @@ PathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) {
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
SourceLocation PathDiagnosticLocation::getValidSourceLocation(
|
||||
const Stmt *S, LocationOrAnalysisDeclContext LAC, bool UseEndOfStatement) {
|
||||
const Stmt *S, StackFrameOrAnalysisDeclContext SFAC,
|
||||
bool UseEndOfStatement) {
|
||||
SourceLocation L = UseEndOfStatement ? S->getEndLoc() : S->getBeginLoc();
|
||||
assert(!LAC.isNull() &&
|
||||
"A valid LocationContext or AnalysisDeclContext should be passed to "
|
||||
assert(!SFAC.isNull() &&
|
||||
"A valid StackFrame or AnalysisDeclContext should be passed to "
|
||||
"PathDiagnosticLocation upon creation.");
|
||||
|
||||
// S might be a temporary statement that does not have a location in the
|
||||
// source code, so find an enclosing statement and use its location.
|
||||
if (!L.isValid()) {
|
||||
AnalysisDeclContext *ADC;
|
||||
if (auto *LC = dyn_cast<const LocationContext *>(LAC))
|
||||
ADC = LC->getAnalysisDeclContext();
|
||||
if (auto *SF = dyn_cast<const StackFrame *>(SFAC))
|
||||
ADC = SF->getAnalysisDeclContext();
|
||||
else
|
||||
ADC = cast<AnalysisDeclContext *>(LAC);
|
||||
ADC = cast<AnalysisDeclContext *>(SFAC);
|
||||
|
||||
ParentMap &PM = ADC->getParentMap();
|
||||
|
||||
|
|
@ -513,9 +514,9 @@ SourceLocation PathDiagnosticLocation::getValidSourceLocation(
|
|||
return L;
|
||||
}
|
||||
|
||||
static PathDiagnosticLocation
|
||||
getLocationForCaller(const StackFrame *SF, const LocationContext *CallerCtx,
|
||||
const SourceManager &SM) {
|
||||
static PathDiagnosticLocation getLocationForCaller(const StackFrame *SF,
|
||||
const StackFrame *CallerSF,
|
||||
const SourceManager &SM) {
|
||||
const CFGBlock &Block = *SF->getCallSiteBlock();
|
||||
CFGElement Source = Block[SF->getIndex()];
|
||||
|
||||
|
|
@ -523,32 +524,32 @@ getLocationForCaller(const StackFrame *SF, const LocationContext *CallerCtx,
|
|||
case CFGElement::Statement:
|
||||
case CFGElement::Constructor:
|
||||
case CFGElement::CXXRecordTypedCall:
|
||||
return PathDiagnosticLocation(Source.castAs<CFGStmt>().getStmt(),
|
||||
SM, CallerCtx);
|
||||
return PathDiagnosticLocation(Source.castAs<CFGStmt>().getStmt(), SM,
|
||||
CallerSF);
|
||||
case CFGElement::Initializer: {
|
||||
const CFGInitializer &Init = Source.castAs<CFGInitializer>();
|
||||
return PathDiagnosticLocation(Init.getInitializer()->getInit(),
|
||||
SM, CallerCtx);
|
||||
return PathDiagnosticLocation(Init.getInitializer()->getInit(), SM,
|
||||
CallerSF);
|
||||
}
|
||||
case CFGElement::AutomaticObjectDtor: {
|
||||
const CFGAutomaticObjDtor &Dtor = Source.castAs<CFGAutomaticObjDtor>();
|
||||
return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(),
|
||||
SM, CallerCtx);
|
||||
return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(), SM,
|
||||
CallerSF);
|
||||
}
|
||||
case CFGElement::DeleteDtor: {
|
||||
const CFGDeleteDtor &Dtor = Source.castAs<CFGDeleteDtor>();
|
||||
return PathDiagnosticLocation(Dtor.getDeleteExpr(), SM, CallerCtx);
|
||||
return PathDiagnosticLocation(Dtor.getDeleteExpr(), SM, CallerSF);
|
||||
}
|
||||
case CFGElement::BaseDtor:
|
||||
case CFGElement::MemberDtor: {
|
||||
const AnalysisDeclContext *CallerInfo = CallerCtx->getAnalysisDeclContext();
|
||||
const AnalysisDeclContext *CallerInfo = CallerSF->getAnalysisDeclContext();
|
||||
if (const Stmt *CallerBody = CallerInfo->getBody())
|
||||
return PathDiagnosticLocation::createEnd(CallerBody, SM, CallerCtx);
|
||||
return PathDiagnosticLocation::createEnd(CallerBody, SM, CallerSF);
|
||||
return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM);
|
||||
}
|
||||
case CFGElement::NewAllocator: {
|
||||
const CFGNewAllocator &Alloc = Source.castAs<CFGNewAllocator>();
|
||||
return PathDiagnosticLocation(Alloc.getAllocatorExpr(), SM, CallerCtx);
|
||||
return PathDiagnosticLocation(Alloc.getAllocatorExpr(), SM, CallerSF);
|
||||
}
|
||||
case CFGElement::TemporaryDtor: {
|
||||
// Temporary destructors are for temporaries. They die immediately at around
|
||||
|
|
@ -556,7 +557,7 @@ getLocationForCaller(const StackFrame *SF, const LocationContext *CallerCtx,
|
|||
// they'd be dealt with via an AutomaticObjectDtor instead.
|
||||
const auto &Dtor = Source.castAs<CFGTemporaryDtor>();
|
||||
return PathDiagnosticLocation::createEnd(Dtor.getBindTemporaryExpr(), SM,
|
||||
CallerCtx);
|
||||
CallerSF);
|
||||
}
|
||||
case CFGElement::ScopeBegin:
|
||||
case CFGElement::ScopeEnd:
|
||||
|
|
@ -578,21 +579,19 @@ PathDiagnosticLocation::createBegin(const Decl *D,
|
|||
}
|
||||
|
||||
PathDiagnosticLocation
|
||||
PathDiagnosticLocation::createBegin(const Stmt *S,
|
||||
const SourceManager &SM,
|
||||
LocationOrAnalysisDeclContext LAC) {
|
||||
PathDiagnosticLocation::createBegin(const Stmt *S, const SourceManager &SM,
|
||||
StackFrameOrAnalysisDeclContext SFAC) {
|
||||
assert(S && "Statement cannot be null");
|
||||
return PathDiagnosticLocation(getValidSourceLocation(S, LAC),
|
||||
SM, SingleLocK);
|
||||
return PathDiagnosticLocation(getValidSourceLocation(S, SFAC), SM,
|
||||
SingleLocK);
|
||||
}
|
||||
|
||||
PathDiagnosticLocation
|
||||
PathDiagnosticLocation::createEnd(const Stmt *S,
|
||||
const SourceManager &SM,
|
||||
LocationOrAnalysisDeclContext LAC) {
|
||||
PathDiagnosticLocation::createEnd(const Stmt *S, const SourceManager &SM,
|
||||
StackFrameOrAnalysisDeclContext SFAC) {
|
||||
if (const auto *CS = dyn_cast<CompoundStmt>(S))
|
||||
return createEndBrace(CS, SM);
|
||||
return PathDiagnosticLocation(getValidSourceLocation(S, LAC, /*End=*/true),
|
||||
return PathDiagnosticLocation(getValidSourceLocation(S, SFAC, /*End=*/true),
|
||||
SM, SingleLocK);
|
||||
}
|
||||
|
||||
|
|
@ -638,10 +637,10 @@ PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS,
|
|||
}
|
||||
|
||||
PathDiagnosticLocation
|
||||
PathDiagnosticLocation::createDeclBegin(const LocationContext *LC,
|
||||
PathDiagnosticLocation::createDeclBegin(const StackFrame *SF,
|
||||
const SourceManager &SM) {
|
||||
// FIXME: Should handle CXXTryStmt if analyser starts supporting C++.
|
||||
if (const auto *CS = dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody()))
|
||||
if (const auto *CS = dyn_cast_or_null<CompoundStmt>(SF->getDecl()->getBody()))
|
||||
if (!CS->body_empty()) {
|
||||
SourceLocation Loc = (*CS->body_begin())->getBeginLoc();
|
||||
return PathDiagnosticLocation(Loc, SM, SingleLocK);
|
||||
|
|
@ -651,9 +650,9 @@ PathDiagnosticLocation::createDeclBegin(const LocationContext *LC,
|
|||
}
|
||||
|
||||
PathDiagnosticLocation
|
||||
PathDiagnosticLocation::createDeclEnd(const LocationContext *LC,
|
||||
PathDiagnosticLocation::createDeclEnd(const StackFrame *SF,
|
||||
const SourceManager &SM) {
|
||||
SourceLocation L = LC->getDecl()->getBodyRBrace();
|
||||
SourceLocation L = SF->getDecl()->getBodyRBrace();
|
||||
return PathDiagnosticLocation(L, SM, SingleLocK);
|
||||
}
|
||||
|
||||
|
|
@ -666,8 +665,8 @@ PathDiagnosticLocation::create(const ProgramPoint& P,
|
|||
if (BSrc->getTerminator().isVirtualBaseBranch()) {
|
||||
// TODO: VirtualBaseBranches should also appear for destructors.
|
||||
// In this case we should put the diagnostic at the end of decl.
|
||||
return PathDiagnosticLocation::createBegin(
|
||||
P.getLocationContext()->getDecl(), SMng);
|
||||
return PathDiagnosticLocation::createBegin(P.getStackFrame()->getDecl(),
|
||||
SMng);
|
||||
|
||||
} else {
|
||||
S = BSrc->getTerminatorCondition();
|
||||
|
|
@ -677,14 +676,14 @@ PathDiagnosticLocation::create(const ProgramPoint& P,
|
|||
// the beginning of a function), use the function's declaration instead.
|
||||
assert(BSrc == &BSrc->getParent()->getEntry() && "CFGBlock has no "
|
||||
"TerminatorCondition and is not the enrty block of the CFG");
|
||||
return PathDiagnosticLocation::createBegin(
|
||||
P.getLocationContext()->getDecl(), SMng);
|
||||
return PathDiagnosticLocation::createBegin(P.getStackFrame()->getDecl(),
|
||||
SMng);
|
||||
}
|
||||
}
|
||||
} else if (std::optional<StmtPoint> SP = P.getAs<StmtPoint>()) {
|
||||
S = SP->getStmt();
|
||||
if (P.getAs<PostStmtPurgeDeadSymbols>())
|
||||
return PathDiagnosticLocation::createEnd(S, SMng, P.getLocationContext());
|
||||
return PathDiagnosticLocation::createEnd(S, SMng, P.getStackFrame());
|
||||
} else if (std::optional<PostInitializer> PIP = P.getAs<PostInitializer>()) {
|
||||
return PathDiagnosticLocation(PIP->getInitializer()->getSourceLocation(),
|
||||
SMng);
|
||||
|
|
@ -694,19 +693,17 @@ PathDiagnosticLocation::create(const ProgramPoint& P,
|
|||
P.getAs<PostImplicitCall>()) {
|
||||
return PathDiagnosticLocation(PIE->getLocation(), SMng);
|
||||
} else if (std::optional<CallEnter> CE = P.getAs<CallEnter>()) {
|
||||
return getLocationForCaller(CE->getCalleeContext(),
|
||||
CE->getLocationContext(),
|
||||
return getLocationForCaller(CE->getCalleeStackFrame(), CE->getStackFrame(),
|
||||
SMng);
|
||||
} else if (std::optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) {
|
||||
return getLocationForCaller(CEE->getCalleeContext(),
|
||||
CEE->getLocationContext(),
|
||||
SMng);
|
||||
return getLocationForCaller(CEE->getCalleeStackFrame(),
|
||||
CEE->getStackFrame(), SMng);
|
||||
} else if (auto CEB = P.getAs<CallExitBegin>()) {
|
||||
if (const ReturnStmt *RS = CEB->getReturnStmt())
|
||||
return PathDiagnosticLocation::createBegin(RS, SMng,
|
||||
CEB->getLocationContext());
|
||||
CEB->getStackFrame());
|
||||
return PathDiagnosticLocation(
|
||||
CEB->getLocationContext()->getDecl()->getSourceRange().getEnd(), SMng);
|
||||
CEB->getStackFrame()->getDecl()->getSourceRange().getEnd(), SMng);
|
||||
} else if (std::optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) {
|
||||
if (std::optional<CFGElement> BlockFront = BE->getFirstElement()) {
|
||||
if (auto StmtElt = BlockFront->getAs<CFGStmt>()) {
|
||||
|
|
@ -722,13 +719,12 @@ PathDiagnosticLocation::create(const ProgramPoint& P,
|
|||
BE->getBlock()->getTerminatorStmt()->getBeginLoc(), SMng);
|
||||
} else if (std::optional<FunctionExitPoint> FE =
|
||||
P.getAs<FunctionExitPoint>()) {
|
||||
return PathDiagnosticLocation(FE->getStmt(), SMng,
|
||||
FE->getLocationContext());
|
||||
return PathDiagnosticLocation(FE->getStmt(), SMng, FE->getStackFrame());
|
||||
} else {
|
||||
llvm_unreachable("Unexpected ProgramPoint");
|
||||
}
|
||||
|
||||
return PathDiagnosticLocation(S, SMng, P.getLocationContext());
|
||||
return PathDiagnosticLocation(S, SMng, P.getStackFrame());
|
||||
}
|
||||
|
||||
PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation(
|
||||
|
|
@ -737,9 +733,8 @@ PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation(
|
|||
return PathDiagnosticLocation(L, L.getManager(), SingleLocK);
|
||||
}
|
||||
|
||||
FullSourceLoc
|
||||
PathDiagnosticLocation::genLocation(SourceLocation L,
|
||||
LocationOrAnalysisDeclContext LAC) const {
|
||||
FullSourceLoc PathDiagnosticLocation::genLocation(
|
||||
SourceLocation L, StackFrameOrAnalysisDeclContext SFAC) const {
|
||||
assert(isValid());
|
||||
// Note that we want a 'switch' here so that the compiler can warn us in
|
||||
// case we add more cases.
|
||||
|
|
@ -751,8 +746,8 @@ FullSourceLoc
|
|||
// Defensive checking.
|
||||
if (!S)
|
||||
break;
|
||||
return FullSourceLoc(getValidSourceLocation(S, LAC),
|
||||
const_cast<SourceManager&>(*SM));
|
||||
return FullSourceLoc(getValidSourceLocation(S, SFAC),
|
||||
const_cast<SourceManager &>(*SM));
|
||||
case DeclK:
|
||||
// Defensive checking.
|
||||
if (!D)
|
||||
|
|
@ -764,7 +759,7 @@ FullSourceLoc
|
|||
}
|
||||
|
||||
PathDiagnosticRange
|
||||
PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const {
|
||||
PathDiagnosticLocation::genRange(StackFrameOrAnalysisDeclContext SFAC) const {
|
||||
assert(isValid());
|
||||
// Note that we want a 'switch' here so that the compiler can warn us in
|
||||
// case we add more cases.
|
||||
|
|
@ -799,7 +794,7 @@ PathDiagnosticRange
|
|||
case Stmt::BinaryConditionalOperatorClass:
|
||||
case Stmt::ConditionalOperatorClass:
|
||||
case Stmt::ObjCForCollectionStmtClass: {
|
||||
SourceLocation L = getValidSourceLocation(S, LAC);
|
||||
SourceLocation L = getValidSourceLocation(S, SFAC);
|
||||
return SourceRange(L, L);
|
||||
}
|
||||
}
|
||||
|
|
@ -844,10 +839,9 @@ void PathDiagnosticLocation::flatten() {
|
|||
std::shared_ptr<PathDiagnosticCallPiece>
|
||||
PathDiagnosticCallPiece::construct(const CallExitEnd &CE,
|
||||
const SourceManager &SM) {
|
||||
const Decl *caller = CE.getLocationContext()->getDecl();
|
||||
PathDiagnosticLocation pos = getLocationForCaller(CE.getCalleeContext(),
|
||||
CE.getLocationContext(),
|
||||
SM);
|
||||
const Decl *caller = CE.getStackFrame()->getDecl();
|
||||
PathDiagnosticLocation pos =
|
||||
getLocationForCaller(CE.getCalleeStackFrame(), CE.getStackFrame(), SM);
|
||||
return std::shared_ptr<PathDiagnosticCallPiece>(
|
||||
new PathDiagnosticCallPiece(caller, pos));
|
||||
}
|
||||
|
|
@ -865,11 +859,11 @@ PathDiagnosticCallPiece::construct(PathPieces &path,
|
|||
|
||||
void PathDiagnosticCallPiece::setCallee(const CallEnter &CE,
|
||||
const SourceManager &SM) {
|
||||
const StackFrame *CalleeSF = CE.getCalleeContext();
|
||||
const StackFrame *CalleeSF = CE.getCalleeStackFrame();
|
||||
Callee = CalleeSF->getDecl();
|
||||
|
||||
callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM);
|
||||
callEnter = getLocationForCaller(CalleeSF, CE.getLocationContext(), SM);
|
||||
callEnter = getLocationForCaller(CalleeSF, CE.getStackFrame(), SM);
|
||||
|
||||
// Autosynthesized property accessors are special because we'd never
|
||||
// pop back up to non-autosynthesized code until we leave them.
|
||||
|
|
|
|||
|
|
@ -21,27 +21,27 @@ using namespace clang;
|
|||
ProgramPointTag::~ProgramPointTag() {}
|
||||
|
||||
ProgramPoint ProgramPoint::getProgramPoint(const Stmt *S, ProgramPoint::Kind K,
|
||||
const LocationContext *LC,
|
||||
const ProgramPointTag *tag){
|
||||
const StackFrame *SF,
|
||||
const ProgramPointTag *tag) {
|
||||
switch (K) {
|
||||
default:
|
||||
llvm_unreachable("Unhandled ProgramPoint kind");
|
||||
case ProgramPoint::PreStmtKind:
|
||||
return PreStmt(S, LC, tag);
|
||||
return PreStmt(S, SF, tag);
|
||||
case ProgramPoint::PostStmtKind:
|
||||
return PostStmt(S, LC, tag);
|
||||
return PostStmt(S, SF, tag);
|
||||
case ProgramPoint::PreLoadKind:
|
||||
return PreLoad(S, LC, tag);
|
||||
return PreLoad(S, SF, tag);
|
||||
case ProgramPoint::PostLoadKind:
|
||||
return PostLoad(S, LC, tag);
|
||||
return PostLoad(S, SF, tag);
|
||||
case ProgramPoint::PreStoreKind:
|
||||
return PreStore(S, LC, tag);
|
||||
return PreStore(S, SF, tag);
|
||||
case ProgramPoint::PostLValueKind:
|
||||
return PostLValue(S, LC, tag);
|
||||
return PostLValue(S, SF, tag);
|
||||
case ProgramPoint::PostStmtPurgeDeadSymbolsKind:
|
||||
return PostStmtPurgeDeadSymbols(S, LC, tag);
|
||||
return PostStmtPurgeDeadSymbols(S, SF, tag);
|
||||
case ProgramPoint::PreStmtPurgeDeadSymbolsKind:
|
||||
return PreStmtPurgeDeadSymbols(S, LC, tag);
|
||||
return PreStmtPurgeDeadSymbols(S, SF, tag);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -166,7 +166,7 @@ std::optional<SourceLocation> ProgramPoint::getSourceLocation() const {
|
|||
|
||||
void ProgramPoint::printJson(llvm::raw_ostream &Out, const char *NL) const {
|
||||
const ASTContext &Context =
|
||||
getLocationContext()->getAnalysisDeclContext()->getASTContext();
|
||||
getStackFrame()->getAnalysisDeclContext()->getASTContext();
|
||||
const SourceManager &SM = Context.getSourceManager();
|
||||
const PrintingPolicy &PP = Context.getPrintingPolicy();
|
||||
const bool AddQuotes = true;
|
||||
|
|
@ -199,7 +199,7 @@ void ProgramPoint::printJson(llvm::raw_ostream &Out, const char *NL) const {
|
|||
case ProgramPoint::CallEnterKind:
|
||||
Out << "CallEnter\", \"callee_decl\": \"";
|
||||
Out << AnalysisDeclContext::getFunctionName(
|
||||
castAs<CallEnter>().getCalleeContext()->getDecl())
|
||||
castAs<CallEnter>().getCalleeStackFrame()->getDecl())
|
||||
<< '\"';
|
||||
break;
|
||||
case ProgramPoint::CallExitBeginKind:
|
||||
|
|
|
|||
|
|
@ -200,8 +200,8 @@ public:
|
|||
checkRegionChanges(ProgramStateRef State,
|
||||
const InvalidatedSymbols *Invalidated,
|
||||
ArrayRef<const MemRegion *> ExplicitRegions,
|
||||
ArrayRef<const MemRegion *> Regions,
|
||||
const LocationContext *LCtx, const CallEvent *Call) const {
|
||||
ArrayRef<const MemRegion *> Regions, const StackFrame *SF,
|
||||
const CallEvent *Call) const {
|
||||
if (isCallbackEnabled(State, "RegionChanges"))
|
||||
llvm::errs() << "RegionChanges\n";
|
||||
return State;
|
||||
|
|
|
|||
|
|
@ -44,16 +44,16 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
|
|||
const SourceManager &SM = B.getSourceManager();
|
||||
llvm::SmallPtrSet<const CFGBlock*, 32> reachable;
|
||||
|
||||
const LocationContext *LC = Eng.getRootLocationContext();
|
||||
const StackFrame *RootSF = Eng.getRootStackFrame();
|
||||
|
||||
const Decl *D = LC->getDecl();
|
||||
const Decl *D = RootSF->getDecl();
|
||||
|
||||
// Iterate over the exploded graph.
|
||||
for (const ExplodedNode &N : G.nodes()) {
|
||||
const ProgramPoint &P = N.getLocation();
|
||||
|
||||
// Only check the coverage in the top level function (optimization).
|
||||
if (D != P.getLocationContext()->getDecl())
|
||||
if (D != P.getStackFrame()->getDecl())
|
||||
continue;
|
||||
|
||||
if (std::optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) {
|
||||
|
|
@ -63,7 +63,7 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
|
|||
}
|
||||
|
||||
// Get the CFG and the Decl of this block.
|
||||
C = LC->getCFG();
|
||||
C = RootSF->getCFG();
|
||||
|
||||
unsigned total = 0, unreachable = 0;
|
||||
|
||||
|
|
@ -124,7 +124,7 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
|
|||
": The analyzer generated a sink at this point";
|
||||
B.EmitBasicReport(
|
||||
D, this, "Sink Point", "Internal Statistics", outputI.str(),
|
||||
PathDiagnosticLocation::createBegin(CS->getStmt(), SM, LC));
|
||||
PathDiagnosticLocation::createBegin(CS->getStmt(), SM, RootSF));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -705,7 +705,7 @@ void ArrayBoundChecker::performCheck(const Expr *E, CheckerContext &C) const {
|
|||
// nicer to say "tainted index".
|
||||
const char *OffsetName = "offset";
|
||||
if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(E))
|
||||
if (isTainted(State, ASE->getIdx(), C.getLocationContext()))
|
||||
if (isTainted(State, ASE->getIdx(), C.getStackFrame()))
|
||||
OffsetName = "index";
|
||||
|
||||
Messages Msgs =
|
||||
|
|
|
|||
|
|
@ -876,7 +876,7 @@ static ProgramStateRef checkElementNonNil(CheckerContext &C,
|
|||
if (!isKnownNonNilCollectionType(FCS->getCollection()->getType()))
|
||||
return State;
|
||||
|
||||
const LocationContext *LCtx = C.getLocationContext();
|
||||
const StackFrame *SF = C.getStackFrame();
|
||||
const Stmt *Element = FCS->getElement();
|
||||
|
||||
// FIXME: Copied from ExprEngineObjC.
|
||||
|
|
@ -884,9 +884,9 @@ static ProgramStateRef checkElementNonNil(CheckerContext &C,
|
|||
if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) {
|
||||
const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl());
|
||||
assert(ElemDecl->getInit() == nullptr);
|
||||
ElementLoc = State->getLValue(ElemDecl, LCtx);
|
||||
ElementLoc = State->getLValue(ElemDecl, SF);
|
||||
} else if (const auto *E = dyn_cast<Expr>(Element)) {
|
||||
ElementLoc = State->getSVal(E, LCtx).getAs<Loc>();
|
||||
ElementLoc = State->getSVal(E, SF).getAs<Loc>();
|
||||
}
|
||||
|
||||
if (!ElementLoc)
|
||||
|
|
@ -966,7 +966,7 @@ void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
|
|||
ProgramStateRef State = C.getState();
|
||||
|
||||
// Check if this is the branch for the end of the loop.
|
||||
if (!ExprEngine::hasMoreIteration(State, FCS, C.getLocationContext())) {
|
||||
if (!ExprEngine::hasMoreIteration(State, FCS, C.getStackFrame())) {
|
||||
if (!alreadyExecutedAtLeastOneLoopIteration(C.getPredecessor(), FCS))
|
||||
State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/false);
|
||||
|
||||
|
|
|
|||
|
|
@ -180,11 +180,11 @@ ProgramStateRef BuiltinFunctionChecker::initStateAftetBuiltinOverflow(
|
|||
auto BoolTy = C.getASTContext().BoolTy;
|
||||
|
||||
ProgramStateRef NewState =
|
||||
State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
|
||||
State->BindExpr(Call.getOriginExpr(), C.getStackFrame(),
|
||||
SVB.makeTruthVal(IsOverflow, BoolTy));
|
||||
|
||||
if (auto L = Call.getArgSVal(2).getAs<Loc>()) {
|
||||
NewState = NewState->bindLoc(*L, RetVal, C.getLocationContext());
|
||||
NewState = NewState->bindLoc(*L, RetVal, C.getStackFrame());
|
||||
|
||||
// Propagate taint if any of the arguments were tainted
|
||||
if (isTainted(State, Arg1) || isTainted(State, Arg2))
|
||||
|
|
@ -255,11 +255,11 @@ bool BuiltinFunctionChecker::evalCall(const CallEvent &Call,
|
|||
if (!FD)
|
||||
return false;
|
||||
|
||||
const LocationContext *LCtx = C.getLocationContext();
|
||||
const StackFrame *SF = C.getStackFrame();
|
||||
const Expr *CE = Call.getOriginExpr();
|
||||
|
||||
if (isBuiltinLikeFunction(Call)) {
|
||||
C.addTransition(state->BindExpr(CE, LCtx, Call.getArgSVal(0)));
|
||||
C.addTransition(state->BindExpr(CE, SF, Call.getArgSVal(0)));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -311,7 +311,7 @@ bool BuiltinFunctionChecker::evalCall(const CallEvent &Call,
|
|||
// are represented the same way in the analyzer.
|
||||
assert (Call.getNumArgs() > 0);
|
||||
SVal Arg = Call.getArgSVal(0);
|
||||
C.addTransition(state->BindExpr(CE, LCtx, Arg));
|
||||
C.addTransition(state->BindExpr(CE, SF, Arg));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -339,7 +339,7 @@ bool BuiltinFunctionChecker::evalCall(const CallEvent &Call,
|
|||
V = SVB.makeIntVal(0, CE->getType());
|
||||
}
|
||||
|
||||
C.addTransition(state->BindExpr(CE, LCtx, V));
|
||||
C.addTransition(state->BindExpr(CE, SF, V));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -107,12 +107,10 @@ public:
|
|||
void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
|
||||
|
||||
ProgramStateRef
|
||||
checkRegionChanges(ProgramStateRef state,
|
||||
const InvalidatedSymbols *,
|
||||
ArrayRef<const MemRegion *> ExplicitRegions,
|
||||
ArrayRef<const MemRegion *> Regions,
|
||||
const LocationContext *LCtx,
|
||||
const CallEvent *Call) const;
|
||||
checkRegionChanges(ProgramStateRef state, const InvalidatedSymbols *,
|
||||
ArrayRef<const MemRegion *> ExplicitRegions,
|
||||
ArrayRef<const MemRegion *> Regions, const StackFrame *SF,
|
||||
const CallEvent *Call) const;
|
||||
|
||||
using FnCheck = std::function<void(const CStringChecker *, CheckerContext &,
|
||||
const CallEvent &)>;
|
||||
|
|
@ -687,9 +685,9 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
|
|||
return state;
|
||||
|
||||
// Get the buffer values and make sure they're known locations.
|
||||
const LocationContext *LCtx = C.getLocationContext();
|
||||
SVal firstVal = state->getSVal(First.Expression, LCtx);
|
||||
SVal secondVal = state->getSVal(Second.Expression, LCtx);
|
||||
const StackFrame *SF = C.getStackFrame();
|
||||
SVal firstVal = state->getSVal(First.Expression, SF);
|
||||
SVal secondVal = state->getSVal(Second.Expression, SF);
|
||||
|
||||
std::optional<Loc> firstLoc = firstVal.getAs<Loc>();
|
||||
if (!firstLoc)
|
||||
|
|
@ -753,7 +751,7 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
|
|||
}
|
||||
|
||||
// Get the length, and make sure it too is known.
|
||||
SVal LengthVal = state->getSVal(Size.Expression, LCtx);
|
||||
SVal LengthVal = state->getSVal(Size.Expression, SF);
|
||||
std::optional<NonLoc> Length = LengthVal.getAs<NonLoc>();
|
||||
if (!Length)
|
||||
return state;
|
||||
|
|
@ -997,10 +995,9 @@ SVal CStringChecker::getCStringLengthForRegion(CheckerContext &C,
|
|||
// Otherwise, get a new symbol and update the state.
|
||||
SValBuilder &svalBuilder = C.getSValBuilder();
|
||||
QualType sizeTy = svalBuilder.getContext().getSizeType();
|
||||
SVal strLength = svalBuilder.getMetadataSymbolVal(CStringChecker::getTag(),
|
||||
MR, Ex, sizeTy,
|
||||
C.getLocationContext(),
|
||||
C.blockCount());
|
||||
SVal strLength =
|
||||
svalBuilder.getMetadataSymbolVal(CStringChecker::getTag(), MR, Ex, sizeTy,
|
||||
C.getStackFrame(), C.blockCount());
|
||||
|
||||
if (!hypothetical) {
|
||||
if (std::optional<NonLoc> strLn = strLength.getAs<NonLoc>()) {
|
||||
|
|
@ -1299,11 +1296,11 @@ ProgramStateRef CStringChecker::invalidateBufferAux(
|
|||
}
|
||||
|
||||
// Invalidate this region.
|
||||
const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
|
||||
const StackFrame *SF = C.getPredecessor()->getStackFrame();
|
||||
RegionAndSymbolInvalidationTraits ITraits;
|
||||
bool CausesPointerEscape = InvalidationTraitOperations(ITraits, R);
|
||||
|
||||
return State->invalidateRegions(R, Elem, C.blockCount(), LCtx,
|
||||
return State->invalidateRegions(R, Elem, C.blockCount(), SF,
|
||||
CausesPointerEscape, nullptr, nullptr,
|
||||
&ITraits);
|
||||
}
|
||||
|
|
@ -1403,8 +1400,8 @@ bool CStringChecker::memsetAux(const Expr *DstBuffer, ConstCFGElementRef Elem,
|
|||
// FIXME: Since there is no perfect way to bind the non-zero character, we
|
||||
// can only deal with zero value here. In the future, we need to deal with
|
||||
// the binding of non-zero value in the case of whole region.
|
||||
State = State->bindDefaultZero(svalBuilder.makeLoc(BR),
|
||||
C.getLocationContext());
|
||||
State =
|
||||
State->bindDefaultZero(svalBuilder.makeLoc(BR), C.getStackFrame());
|
||||
} else {
|
||||
// If the destination buffer's extent is not equal to the value of
|
||||
// third argument, just invalidate buffer.
|
||||
|
|
@ -1420,7 +1417,7 @@ bool CStringChecker::memsetAux(const Expr *DstBuffer, ConstCFGElementRef Elem,
|
|||
} else if (!StateNullChar && StateNonNullChar) {
|
||||
SVal NewStrLen = svalBuilder.getMetadataSymbolVal(
|
||||
CStringChecker::getTag(), MR, DstBuffer, Ctx.getSizeType(),
|
||||
C.getLocationContext(), C.blockCount());
|
||||
C.getStackFrame(), C.blockCount());
|
||||
|
||||
// If the value of second argument is not zero, then the string length
|
||||
// is at least the size argument.
|
||||
|
|
@ -1452,8 +1449,8 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallEvent &Call,
|
|||
CurrentFunctionDescription = "memory copy function";
|
||||
|
||||
// See if the size argument is zero.
|
||||
const LocationContext *LCtx = C.getLocationContext();
|
||||
SVal sizeVal = state->getSVal(Size.Expression, LCtx);
|
||||
const StackFrame *SF = C.getStackFrame();
|
||||
SVal sizeVal = state->getSVal(Size.Expression, SF);
|
||||
QualType sizeTy = Size.Expression->getType();
|
||||
|
||||
ProgramStateRef stateZeroSize, stateNonZeroSize;
|
||||
|
|
@ -1461,13 +1458,12 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallEvent &Call,
|
|||
assumeZero(C, state, sizeVal, sizeTy);
|
||||
|
||||
// Get the value of the Dest.
|
||||
SVal destVal = state->getSVal(Dest.Expression, LCtx);
|
||||
SVal destVal = state->getSVal(Dest.Expression, SF);
|
||||
|
||||
// If the size is zero, there won't be any actual memory access, so
|
||||
// just bind the return value to the destination buffer and return.
|
||||
if (stateZeroSize && !stateNonZeroSize) {
|
||||
stateZeroSize =
|
||||
stateZeroSize->BindExpr(Call.getOriginExpr(), LCtx, destVal);
|
||||
stateZeroSize = stateZeroSize->BindExpr(Call.getOriginExpr(), SF, destVal);
|
||||
C.addTransition(stateZeroSize);
|
||||
return;
|
||||
}
|
||||
|
|
@ -1486,7 +1482,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallEvent &Call,
|
|||
return;
|
||||
|
||||
// Get the value of the Src.
|
||||
SVal srcVal = state->getSVal(Source.Expression, LCtx);
|
||||
SVal srcVal = state->getSVal(Source.Expression, SF);
|
||||
|
||||
// Ensure the source is not null. If it is NULL there will be a
|
||||
// NULL pointer dereference.
|
||||
|
|
@ -1521,11 +1517,11 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallEvent &Call,
|
|||
lastElement = C.getSValBuilder().conjureSymbolVal(Call, C.blockCount());
|
||||
|
||||
// The byte after the last byte copied is the return value.
|
||||
state = state->BindExpr(Call.getOriginExpr(), LCtx, lastElement);
|
||||
state = state->BindExpr(Call.getOriginExpr(), SF, lastElement);
|
||||
} else {
|
||||
// All other copies return the destination buffer.
|
||||
// (Well, bcopy() has a void return type, but this won't hurt.)
|
||||
state = state->BindExpr(Call.getOriginExpr(), LCtx, destVal);
|
||||
state = state->BindExpr(Call.getOriginExpr(), SF, destVal);
|
||||
}
|
||||
|
||||
// Invalidate the destination (regular invalidation without pointer-escaping
|
||||
|
|
@ -1613,10 +1609,10 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallEvent &Call,
|
|||
|
||||
ProgramStateRef State = C.getState();
|
||||
SValBuilder &Builder = C.getSValBuilder();
|
||||
const LocationContext *LCtx = C.getLocationContext();
|
||||
const StackFrame *SF = C.getStackFrame();
|
||||
|
||||
// See if the size argument is zero.
|
||||
SVal sizeVal = State->getSVal(Size.Expression, LCtx);
|
||||
SVal sizeVal = State->getSVal(Size.Expression, SF);
|
||||
QualType sizeTy = Size.Expression->getType();
|
||||
|
||||
ProgramStateRef stateZeroSize, stateNonZeroSize;
|
||||
|
|
@ -1627,7 +1623,7 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallEvent &Call,
|
|||
// have to check either of the buffers.
|
||||
if (stateZeroSize) {
|
||||
State = stateZeroSize;
|
||||
State = State->BindExpr(Call.getOriginExpr(), LCtx,
|
||||
State = State->BindExpr(Call.getOriginExpr(), SF,
|
||||
Builder.makeZeroVal(Call.getResultType()));
|
||||
C.addTransition(State);
|
||||
}
|
||||
|
|
@ -1639,9 +1635,9 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallEvent &Call,
|
|||
// First, get the two buffers' addresses. Another checker will have already
|
||||
// made sure they're not undefined.
|
||||
DefinedOrUnknownSVal LV =
|
||||
State->getSVal(Left.Expression, LCtx).castAs<DefinedOrUnknownSVal>();
|
||||
State->getSVal(Left.Expression, SF).castAs<DefinedOrUnknownSVal>();
|
||||
DefinedOrUnknownSVal RV =
|
||||
State->getSVal(Right.Expression, LCtx).castAs<DefinedOrUnknownSVal>();
|
||||
State->getSVal(Right.Expression, SF).castAs<DefinedOrUnknownSVal>();
|
||||
|
||||
// See if they are the same.
|
||||
ProgramStateRef SameBuffer, NotSameBuffer;
|
||||
|
|
@ -1654,7 +1650,7 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallEvent &Call,
|
|||
State = SameBuffer;
|
||||
State = CheckBufferAccess(C, State, Left, Size, AccessKind::read);
|
||||
if (State) {
|
||||
State = SameBuffer->BindExpr(Call.getOriginExpr(), LCtx,
|
||||
State = SameBuffer->BindExpr(Call.getOriginExpr(), SF,
|
||||
Builder.makeZeroVal(Call.getResultType()));
|
||||
C.addTransition(State);
|
||||
}
|
||||
|
|
@ -1669,7 +1665,7 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallEvent &Call,
|
|||
if (State) {
|
||||
// The return value is the comparison result, which we don't know.
|
||||
SVal CmpV = Builder.conjureSymbolVal(Call, C.blockCount());
|
||||
State = State->BindExpr(Call.getOriginExpr(), LCtx, CmpV);
|
||||
State = State->BindExpr(Call.getOriginExpr(), SF, CmpV);
|
||||
C.addTransition(State);
|
||||
}
|
||||
}
|
||||
|
|
@ -1692,11 +1688,11 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C,
|
|||
bool IsStrnlen) const {
|
||||
CurrentFunctionDescription = "string length function";
|
||||
ProgramStateRef state = C.getState();
|
||||
const LocationContext *LCtx = C.getLocationContext();
|
||||
const StackFrame *SF = C.getStackFrame();
|
||||
|
||||
if (IsStrnlen) {
|
||||
const Expr *maxlenExpr = Call.getArgExpr(1);
|
||||
SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
|
||||
SVal maxlenVal = state->getSVal(maxlenExpr, SF);
|
||||
|
||||
ProgramStateRef stateZeroSize, stateNonZeroSize;
|
||||
std::tie(stateZeroSize, stateNonZeroSize) =
|
||||
|
|
@ -1706,7 +1702,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C,
|
|||
// have to check the string itself.
|
||||
if (stateZeroSize) {
|
||||
SVal zero = C.getSValBuilder().makeZeroVal(Call.getResultType());
|
||||
stateZeroSize = stateZeroSize->BindExpr(Call.getOriginExpr(), LCtx, zero);
|
||||
stateZeroSize = stateZeroSize->BindExpr(Call.getOriginExpr(), SF, zero);
|
||||
C.addTransition(stateZeroSize);
|
||||
}
|
||||
|
||||
|
|
@ -1720,7 +1716,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C,
|
|||
|
||||
// Check that the string argument is non-null.
|
||||
AnyArgExpr Arg = {Call.getArgExpr(0), 0};
|
||||
SVal ArgVal = state->getSVal(Arg.Expression, LCtx);
|
||||
SVal ArgVal = state->getSVal(Arg.Expression, SF);
|
||||
state = checkNonNull(C, state, Arg, ArgVal);
|
||||
|
||||
if (!state)
|
||||
|
|
@ -1743,7 +1739,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C,
|
|||
// It's a little unfortunate to be getting this again,
|
||||
// but it's not that expensive...
|
||||
const Expr *maxlenExpr = Call.getArgExpr(1);
|
||||
SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
|
||||
SVal maxlenVal = state->getSVal(maxlenExpr, SF);
|
||||
|
||||
std::optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>();
|
||||
std::optional<NonLoc> maxlenValNL = maxlenVal.getAs<NonLoc>();
|
||||
|
|
@ -1800,7 +1796,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C,
|
|||
|
||||
// Bind the return value.
|
||||
assert(!result.isUnknown() && "Should have conjured a value by now");
|
||||
state = state->BindExpr(Call.getOriginExpr(), LCtx, result);
|
||||
state = state->BindExpr(Call.getOriginExpr(), SF, result);
|
||||
C.addTransition(state);
|
||||
}
|
||||
|
||||
|
|
@ -1881,18 +1877,18 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallEvent &Call,
|
|||
CurrentFunctionDescription = "string concatenation function";
|
||||
|
||||
ProgramStateRef state = C.getState();
|
||||
const LocationContext *LCtx = C.getLocationContext();
|
||||
const StackFrame *SF = C.getStackFrame();
|
||||
|
||||
// Check that the destination is non-null.
|
||||
DestinationArgExpr Dst = {{Call.getArgExpr(0), 0}};
|
||||
SVal DstVal = state->getSVal(Dst.Expression, LCtx);
|
||||
SVal DstVal = state->getSVal(Dst.Expression, SF);
|
||||
state = checkNonNull(C, state, Dst, DstVal);
|
||||
if (!state)
|
||||
return;
|
||||
|
||||
// Check that the source is non-null.
|
||||
SourceArgExpr srcExpr = {{Call.getArgExpr(1), 1}};
|
||||
SVal srcVal = state->getSVal(srcExpr.Expression, LCtx);
|
||||
SVal srcVal = state->getSVal(srcExpr.Expression, SF);
|
||||
state = checkNonNull(C, state, srcExpr, srcVal);
|
||||
if (!state)
|
||||
return;
|
||||
|
|
@ -1936,7 +1932,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallEvent &Call,
|
|||
if (IsBounded) {
|
||||
// Get the max number of characters to copy.
|
||||
SizeArgExpr lenExpr = {{Call.getArgExpr(2), 2}};
|
||||
SVal lenVal = state->getSVal(lenExpr.Expression, LCtx);
|
||||
SVal lenVal = state->getSVal(lenExpr.Expression, SF);
|
||||
|
||||
// Protect against misdeclared strncpy().
|
||||
lenVal =
|
||||
|
|
@ -2050,18 +2046,18 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallEvent &Call,
|
|||
if (StateZeroSize && !StateNonZeroSize) {
|
||||
if (returnPtr) {
|
||||
StateZeroSize =
|
||||
StateZeroSize->BindExpr(Call.getOriginExpr(), LCtx, DstVal);
|
||||
StateZeroSize->BindExpr(Call.getOriginExpr(), SF, DstVal);
|
||||
} else {
|
||||
if (appendK == ConcatFnKind::none) {
|
||||
// strlcpy returns strlen(src)
|
||||
StateZeroSize = StateZeroSize->BindExpr(Call.getOriginExpr(),
|
||||
LCtx, strLength);
|
||||
StateZeroSize =
|
||||
StateZeroSize->BindExpr(Call.getOriginExpr(), SF, strLength);
|
||||
} else {
|
||||
// strlcat returns strlen(src) + strlen(dst)
|
||||
SVal retSize = svalBuilder.evalBinOp(
|
||||
state, BO_Add, strLength, dstStrLength, sizeTy);
|
||||
StateZeroSize =
|
||||
StateZeroSize->BindExpr(Call.getOriginExpr(), LCtx, retSize);
|
||||
StateZeroSize->BindExpr(Call.getOriginExpr(), SF, retSize);
|
||||
}
|
||||
}
|
||||
C.addTransition(StateZeroSize);
|
||||
|
|
@ -2253,7 +2249,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallEvent &Call,
|
|||
if (CouldAccessOutOfBound) {
|
||||
// Get the max number of characters to copy.
|
||||
const Expr *LenExpr = Call.getArgExpr(2);
|
||||
SVal LenVal = state->getSVal(LenExpr, LCtx);
|
||||
SVal LenVal = state->getSVal(LenExpr, SF);
|
||||
|
||||
// Protect against misdeclared strncpy().
|
||||
LenVal = svalBuilder.evalCast(LenVal, sizeTy, LenExpr->getType());
|
||||
|
|
@ -2307,7 +2303,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallEvent &Call,
|
|||
}
|
||||
}
|
||||
// Set the return value.
|
||||
state = state->BindExpr(Call.getOriginExpr(), LCtx, Result);
|
||||
state = state->BindExpr(Call.getOriginExpr(), SF, Result);
|
||||
C.addTransition(state);
|
||||
}
|
||||
|
||||
|
|
@ -2317,7 +2313,7 @@ void CStringChecker::evalStrxfrm(CheckerContext &C,
|
|||
CurrentFunctionDescription = "locale transformation function";
|
||||
|
||||
ProgramStateRef State = C.getState();
|
||||
const LocationContext *LCtx = C.getLocationContext();
|
||||
const StackFrame *SF = C.getStackFrame();
|
||||
SValBuilder &SVB = C.getSValBuilder();
|
||||
|
||||
// Get arguments
|
||||
|
|
@ -2326,7 +2322,7 @@ void CStringChecker::evalStrxfrm(CheckerContext &C,
|
|||
SizeArgExpr Size = {{Call.getArgExpr(2), 2}};
|
||||
|
||||
// `src` can never be null
|
||||
SVal SrcVal = State->getSVal(Source.Expression, LCtx);
|
||||
SVal SrcVal = State->getSVal(Source.Expression, SF);
|
||||
State = checkNonNull(C, State, Source, SrcVal);
|
||||
if (!State)
|
||||
return;
|
||||
|
|
@ -2340,16 +2336,16 @@ void CStringChecker::evalStrxfrm(CheckerContext &C,
|
|||
// transformation
|
||||
SVal RetVal = SVB.conjureSymbolVal(Call, C.blockCount());
|
||||
|
||||
auto BindReturnAndTransition = [&RetVal, &Call, LCtx,
|
||||
auto BindReturnAndTransition = [&RetVal, &Call, SF,
|
||||
&C](ProgramStateRef State) {
|
||||
if (State) {
|
||||
State = State->BindExpr(Call.getOriginExpr(), LCtx, RetVal);
|
||||
State = State->BindExpr(Call.getOriginExpr(), SF, RetVal);
|
||||
C.addTransition(State);
|
||||
}
|
||||
};
|
||||
|
||||
// Check if size is zero
|
||||
SVal SizeVal = State->getSVal(Size.Expression, LCtx);
|
||||
SVal SizeVal = State->getSVal(Size.Expression, SF);
|
||||
QualType SizeTy = Size.Expression->getType();
|
||||
|
||||
auto [StateZeroSize, StateSizeNonZero] =
|
||||
|
|
@ -2364,7 +2360,7 @@ void CStringChecker::evalStrxfrm(CheckerContext &C,
|
|||
return BindReturnAndTransition(StateZeroSize);
|
||||
|
||||
// If `n` is not 0, `dest` can not be null.
|
||||
SVal DestVal = StateSizeNonZero->getSVal(Dest.Expression, LCtx);
|
||||
SVal DestVal = StateSizeNonZero->getSVal(Dest.Expression, SF);
|
||||
StateSizeNonZero = checkNonNull(C, StateSizeNonZero, Dest, DestVal);
|
||||
if (!StateSizeNonZero)
|
||||
return;
|
||||
|
|
@ -2404,7 +2400,7 @@ void CStringChecker::evalStrxfrm(CheckerContext &C,
|
|||
if (auto DestLoc = DestVal.getAs<loc::MemRegionVal>()) {
|
||||
StateFailure = StateFailure->killBinding(*DestLoc);
|
||||
StateFailure =
|
||||
StateFailure->bindDefaultInitial(*DestLoc, UndefinedVal{}, LCtx);
|
||||
StateFailure->bindDefaultInitial(*DestLoc, UndefinedVal{}, SF);
|
||||
}
|
||||
|
||||
BindReturnAndTransition(StateFailure);
|
||||
|
|
@ -2439,18 +2435,18 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallEvent &Call,
|
|||
bool IsBounded, bool IgnoreCase) const {
|
||||
CurrentFunctionDescription = "string comparison function";
|
||||
ProgramStateRef state = C.getState();
|
||||
const LocationContext *LCtx = C.getLocationContext();
|
||||
const StackFrame *SF = C.getStackFrame();
|
||||
|
||||
// Check that the first string is non-null
|
||||
AnyArgExpr Left = {Call.getArgExpr(0), 0};
|
||||
SVal LeftVal = state->getSVal(Left.Expression, LCtx);
|
||||
SVal LeftVal = state->getSVal(Left.Expression, SF);
|
||||
state = checkNonNull(C, state, Left, LeftVal);
|
||||
if (!state)
|
||||
return;
|
||||
|
||||
// Check that the second string is non-null.
|
||||
AnyArgExpr Right = {Call.getArgExpr(1), 1};
|
||||
SVal RightVal = state->getSVal(Right.Expression, LCtx);
|
||||
SVal RightVal = state->getSVal(Right.Expression, SF);
|
||||
state = checkNonNull(C, state, Right, RightVal);
|
||||
if (!state)
|
||||
return;
|
||||
|
|
@ -2481,7 +2477,7 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallEvent &Call,
|
|||
// and we only need to check one size.
|
||||
if (StSameBuf) {
|
||||
StSameBuf =
|
||||
StSameBuf->BindExpr(Call.getOriginExpr(), LCtx,
|
||||
StSameBuf->BindExpr(Call.getOriginExpr(), SF,
|
||||
svalBuilder.makeZeroVal(Call.getResultType()));
|
||||
C.addTransition(StSameBuf);
|
||||
|
||||
|
|
@ -2511,7 +2507,7 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallEvent &Call,
|
|||
if (IsBounded) {
|
||||
// Get the max number of characters to compare.
|
||||
const Expr *lenExpr = Call.getArgExpr(2);
|
||||
SVal lenVal = state->getSVal(lenExpr, LCtx);
|
||||
SVal lenVal = state->getSVal(lenExpr, SF);
|
||||
|
||||
// If the length is known, we can get the right substrings.
|
||||
if (const llvm::APSInt *len = svalBuilder.getKnownValue(state, lenVal)) {
|
||||
|
|
@ -2558,7 +2554,7 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallEvent &Call,
|
|||
}
|
||||
}
|
||||
|
||||
state = state->BindExpr(Call.getOriginExpr(), LCtx, resultVal);
|
||||
state = state->BindExpr(Call.getOriginExpr(), SF, resultVal);
|
||||
|
||||
// Record this as a possible path.
|
||||
C.addTransition(state);
|
||||
|
|
@ -2577,18 +2573,18 @@ void CStringChecker::evalStrsep(CheckerContext &C,
|
|||
|
||||
CurrentFunctionDescription = "strsep()";
|
||||
ProgramStateRef State = C.getState();
|
||||
const LocationContext *LCtx = C.getLocationContext();
|
||||
const StackFrame *SF = C.getStackFrame();
|
||||
|
||||
// Check that the search string pointer is non-null (though it may point to
|
||||
// a null string).
|
||||
SVal SearchStrVal = State->getSVal(SearchStrPtr.Expression, LCtx);
|
||||
SVal SearchStrVal = State->getSVal(SearchStrPtr.Expression, SF);
|
||||
State = checkNonNull(C, State, SearchStrPtr, SearchStrVal);
|
||||
if (!State)
|
||||
return;
|
||||
|
||||
// Check that the delimiter string is non-null.
|
||||
AnyArgExpr DelimStr = {Call.getArgExpr(1), 1};
|
||||
SVal DelimStrVal = State->getSVal(DelimStr.Expression, LCtx);
|
||||
SVal DelimStrVal = State->getSVal(DelimStr.Expression, SF);
|
||||
State = checkNonNull(C, State, DelimStr, DelimStrVal);
|
||||
if (!State)
|
||||
return;
|
||||
|
|
@ -2609,7 +2605,7 @@ void CStringChecker::evalStrsep(CheckerContext &C,
|
|||
// further along in the same string, or NULL if there are no more tokens.
|
||||
State = State->bindLoc(*SearchStrLoc,
|
||||
SVB.conjureSymbolVal(Call, C.blockCount(), getTag()),
|
||||
LCtx);
|
||||
SF);
|
||||
} else {
|
||||
assert(SearchStrVal.isUnknown());
|
||||
// Conjure a symbolic value. It's the best we can do.
|
||||
|
|
@ -2617,7 +2613,7 @@ void CStringChecker::evalStrsep(CheckerContext &C,
|
|||
}
|
||||
|
||||
// Set the return value, and finish.
|
||||
State = State->BindExpr(Call.getOriginExpr(), LCtx, Result);
|
||||
State = State->BindExpr(Call.getOriginExpr(), SF, Result);
|
||||
C.addTransition(State);
|
||||
}
|
||||
|
||||
|
|
@ -2639,7 +2635,7 @@ void CStringChecker::evalStdCopyCommon(CheckerContext &C,
|
|||
|
||||
ProgramStateRef State = C.getState();
|
||||
|
||||
const LocationContext *LCtx = C.getLocationContext();
|
||||
const StackFrame *SF = C.getStackFrame();
|
||||
|
||||
// template <class _InputIterator, class _OutputIterator>
|
||||
// _OutputIterator
|
||||
|
|
@ -2648,7 +2644,7 @@ void CStringChecker::evalStdCopyCommon(CheckerContext &C,
|
|||
|
||||
// Invalidate the destination buffer
|
||||
const Expr *Dst = Call.getArgExpr(2);
|
||||
SVal DstVal = State->getSVal(Dst, LCtx);
|
||||
SVal DstVal = State->getSVal(Dst, SF);
|
||||
// FIXME: As we do not know how many items are copied, we also invalidate the
|
||||
// super region containing the target location.
|
||||
State = invalidateDestinationBufferAlwaysEscapeSuperRegion(
|
||||
|
|
@ -2657,7 +2653,7 @@ void CStringChecker::evalStdCopyCommon(CheckerContext &C,
|
|||
SValBuilder &SVB = C.getSValBuilder();
|
||||
|
||||
SVal ResultVal = SVB.conjureSymbolVal(Call, C.blockCount());
|
||||
State = State->BindExpr(Call.getOriginExpr(), LCtx, ResultVal);
|
||||
State = State->BindExpr(Call.getOriginExpr(), SF, ResultVal);
|
||||
|
||||
C.addTransition(State);
|
||||
}
|
||||
|
|
@ -2674,7 +2670,7 @@ void CStringChecker::evalMemset(CheckerContext &C,
|
|||
ProgramStateRef State = C.getState();
|
||||
|
||||
// See if the size argument is zero.
|
||||
const LocationContext *LCtx = C.getLocationContext();
|
||||
const StackFrame *SF = C.getStackFrame();
|
||||
SVal SizeVal = C.getSVal(Size.Expression);
|
||||
QualType SizeTy = Size.Expression->getType();
|
||||
|
||||
|
|
@ -2687,7 +2683,7 @@ void CStringChecker::evalMemset(CheckerContext &C,
|
|||
// If the size is zero, there won't be any actual memory access, so
|
||||
// just bind the return value to the buffer and return.
|
||||
if (ZeroSize && !NonZeroSize) {
|
||||
ZeroSize = ZeroSize->BindExpr(Call.getOriginExpr(), LCtx, BufferPtrVal);
|
||||
ZeroSize = ZeroSize->BindExpr(Call.getOriginExpr(), SF, BufferPtrVal);
|
||||
C.addTransition(ZeroSize);
|
||||
return;
|
||||
}
|
||||
|
|
@ -2709,7 +2705,7 @@ void CStringChecker::evalMemset(CheckerContext &C,
|
|||
C.getSVal(CharE.Expression), Size.Expression, C, State))
|
||||
return;
|
||||
|
||||
State = State->BindExpr(Call.getOriginExpr(), LCtx, BufferPtrVal);
|
||||
State = State->BindExpr(Call.getOriginExpr(), SF, BufferPtrVal);
|
||||
C.addTransition(State);
|
||||
}
|
||||
|
||||
|
|
@ -2882,7 +2878,7 @@ void CStringChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
|
|||
if (!isa<StringLiteral>(Init))
|
||||
continue;
|
||||
|
||||
Loc VarLoc = state->getLValue(D, C.getLocationContext());
|
||||
Loc VarLoc = state->getLValue(D, C.getStackFrame());
|
||||
const MemRegion *MR = VarLoc.getAsRegion();
|
||||
if (!MR)
|
||||
continue;
|
||||
|
|
@ -2898,12 +2894,10 @@ void CStringChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
|
|||
C.addTransition(state);
|
||||
}
|
||||
|
||||
ProgramStateRef
|
||||
CStringChecker::checkRegionChanges(ProgramStateRef state,
|
||||
const InvalidatedSymbols *,
|
||||
ProgramStateRef CStringChecker::checkRegionChanges(
|
||||
ProgramStateRef state, const InvalidatedSymbols *,
|
||||
ArrayRef<const MemRegion *> ExplicitRegions,
|
||||
ArrayRef<const MemRegion *> Regions,
|
||||
const LocationContext *LCtx,
|
||||
ArrayRef<const MemRegion *> Regions, const StackFrame *SF,
|
||||
const CallEvent *Call) const {
|
||||
CStringLengthTy Entries = state->get<CStringLength>();
|
||||
if (Entries.isEmpty())
|
||||
|
|
|
|||
|
|
@ -210,8 +210,7 @@ CXXDeleteChecker::PtrCastVisitor::VisitNode(const ExplodedNode *N,
|
|||
OS << "Casting from '" << SourceType.getAsString() << "' to '"
|
||||
<< TargetType.getAsString() << "' here";
|
||||
|
||||
PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
|
||||
N->getLocationContext());
|
||||
PathDiagnosticLocation Pos(S, BRC.getSourceManager(), N->getStackFrame());
|
||||
return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(),
|
||||
/*addPosRange=*/true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,20 +38,19 @@ CXXSelfAssignmentChecker::CXXSelfAssignmentChecker() {}
|
|||
void CXXSelfAssignmentChecker::checkBeginFunction(CheckerContext &C) const {
|
||||
if (!C.inTopFrame())
|
||||
return;
|
||||
const auto *LCtx = C.getLocationContext();
|
||||
const auto *MD = dyn_cast<CXXMethodDecl>(LCtx->getDecl());
|
||||
const auto *SF = C.getStackFrame();
|
||||
const auto *MD = dyn_cast<CXXMethodDecl>(SF->getDecl());
|
||||
if (!MD)
|
||||
return;
|
||||
if (!MD->isCopyAssignmentOperator() && !MD->isMoveAssignmentOperator())
|
||||
return;
|
||||
auto &State = C.getState();
|
||||
auto &SVB = C.getSValBuilder();
|
||||
auto ThisVal =
|
||||
State->getSVal(SVB.getCXXThis(MD, LCtx->getStackFrame()));
|
||||
auto Param = SVB.makeLoc(State->getRegion(MD->getParamDecl(0), LCtx));
|
||||
auto ThisVal = State->getSVal(SVB.getCXXThis(MD, SF));
|
||||
auto Param = SVB.makeLoc(State->getRegion(MD->getParamDecl(0), SF));
|
||||
auto ParamVal = State->getSVal(Param);
|
||||
|
||||
ProgramStateRef SelfAssignState = State->bindLoc(Param, ThisVal, LCtx);
|
||||
ProgramStateRef SelfAssignState = State->bindLoc(Param, ThisVal, SF);
|
||||
const NoteTag *SelfAssignTag =
|
||||
C.getNoteTag([MD](PathSensitiveBugReport &BR) -> std::string {
|
||||
SmallString<256> Msg;
|
||||
|
|
@ -61,7 +60,7 @@ void CXXSelfAssignmentChecker::checkBeginFunction(CheckerContext &C) const {
|
|||
});
|
||||
C.addTransition(SelfAssignState, SelfAssignTag);
|
||||
|
||||
ProgramStateRef NonSelfAssignState = State->bindLoc(Param, ParamVal, LCtx);
|
||||
ProgramStateRef NonSelfAssignState = State->bindLoc(Param, ParamVal, SF);
|
||||
const NoteTag *NonSelfAssignTag =
|
||||
C.getNoteTag([MD](PathSensitiveBugReport &BR) -> std::string {
|
||||
SmallString<256> Msg;
|
||||
|
|
|
|||
|
|
@ -430,8 +430,7 @@ ProgramStateRef CallAndMessageChecker::checkFunctionPointerCall(
|
|||
const CallExpr *CE, CheckerContext &C, ProgramStateRef State) const {
|
||||
|
||||
const Expr *Callee = CE->getCallee()->IgnoreParens();
|
||||
const LocationContext *LCtx = C.getLocationContext();
|
||||
SVal L = State->getSVal(Callee, LCtx);
|
||||
SVal L = State->getSVal(Callee, C.getStackFrame());
|
||||
|
||||
if (L.isUndef()) {
|
||||
if (!ChecksEnabled[CK_FunctionPointer]) {
|
||||
|
|
@ -700,18 +699,18 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
|
|||
// return different values depending on the return type and the architecture.
|
||||
QualType RetTy = Msg.getResultType();
|
||||
CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
|
||||
const LocationContext *LCtx = C.getLocationContext();
|
||||
const StackFrame *SF = C.getStackFrame();
|
||||
|
||||
if (CanRetTy->isStructureOrClassType()) {
|
||||
// Structure returns are safe since the compiler zeroes them out.
|
||||
SVal V = C.getSValBuilder().makeZeroVal(RetTy);
|
||||
C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V));
|
||||
C.addTransition(state->BindExpr(Msg.getOriginExpr(), SF, V));
|
||||
return;
|
||||
}
|
||||
|
||||
// Other cases: check if sizeof(return type) > sizeof(void*)
|
||||
if (CanRetTy != Ctx.VoidTy && C.getLocationContext()->getParentMap()
|
||||
.isConsumedExpr(Msg.getOriginExpr())) {
|
||||
if (CanRetTy != Ctx.VoidTy &&
|
||||
C.getStackFrame()->getParentMap().isConsumedExpr(Msg.getOriginExpr())) {
|
||||
// Compute: sizeof(void *) and sizeof(return type)
|
||||
const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
|
||||
const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);
|
||||
|
|
@ -743,7 +742,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
|
|||
// of this case unless we have *a lot* more knowledge.
|
||||
//
|
||||
SVal V = C.getSValBuilder().makeZeroVal(RetTy);
|
||||
C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V));
|
||||
C.addTransition(state->BindExpr(Msg.getOriginExpr(), SF, V));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -252,7 +252,7 @@ static void addCastTransition(const CallEvent &Call, DefinedOrUnknownSVal DV,
|
|||
SVal V = CastSucceeds ? C.getSValBuilder().evalCast(DV, CastToTy, CastFromTy)
|
||||
: C.getSValBuilder().makeNullWithType(CastToTy);
|
||||
C.addTransition(
|
||||
State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), V, false),
|
||||
State->BindExpr(Call.getOriginExpr(), C.getStackFrame(), V, false),
|
||||
getNoteTag(C, CastInfo, CastToTy, Object, CastSucceeds, IsKnownCast));
|
||||
}
|
||||
|
||||
|
|
@ -313,11 +313,11 @@ static void addInstanceOfTransition(const CallEvent &Call,
|
|||
|
||||
if (CastSucceeds) {
|
||||
Success = true;
|
||||
C.addTransition(
|
||||
NewState->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
|
||||
C.getSValBuilder().makeTruthVal(true)),
|
||||
getNoteTag(C, CastInfo, CastToTy, Call.getArgExpr(0), true,
|
||||
IsKnownCast));
|
||||
C.addTransition(NewState->BindExpr(Call.getOriginExpr(),
|
||||
C.getStackFrame(),
|
||||
C.getSValBuilder().makeTruthVal(true)),
|
||||
getNoteTag(C, CastInfo, CastToTy, Call.getArgExpr(0),
|
||||
true, IsKnownCast));
|
||||
if (IsKnownCast)
|
||||
return;
|
||||
} else if (CastInfo && CastInfo->succeeds()) {
|
||||
|
|
@ -327,10 +327,9 @@ static void addInstanceOfTransition(const CallEvent &Call,
|
|||
}
|
||||
|
||||
if (!Success) {
|
||||
C.addTransition(
|
||||
State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
|
||||
C.getSValBuilder().makeTruthVal(false)),
|
||||
getNoteTag(C, CastToTyVec, Call.getArgExpr(0), IsAnyKnown));
|
||||
C.addTransition(State->BindExpr(Call.getOriginExpr(), C.getStackFrame(),
|
||||
C.getSValBuilder().makeTruthVal(false)),
|
||||
getNoteTag(C, CastToTyVec, Call.getArgExpr(0), IsAnyKnown));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -357,8 +356,7 @@ static void evalNullParamNullReturn(const CallEvent &Call,
|
|||
DefinedOrUnknownSVal DV,
|
||||
CheckerContext &C) {
|
||||
if (ProgramStateRef State = C.getState()->assume(DV, false))
|
||||
C.addTransition(State->BindExpr(Call.getOriginExpr(),
|
||||
C.getLocationContext(),
|
||||
C.addTransition(State->BindExpr(Call.getOriginExpr(), C.getStackFrame(),
|
||||
C.getSValBuilder().makeNullWithType(
|
||||
Call.getOriginExpr()->getType()),
|
||||
false),
|
||||
|
|
|
|||
|
|
@ -157,14 +157,14 @@ private:
|
|||
getDeallocReleaseRequirement(const ObjCPropertyImplDecl *PropImpl) const;
|
||||
|
||||
bool isInInstanceDealloc(const CheckerContext &C, SVal &SelfValOut) const;
|
||||
bool isInInstanceDealloc(const CheckerContext &C, const LocationContext *LCtx,
|
||||
bool isInInstanceDealloc(const CheckerContext &C, const StackFrame *SF,
|
||||
SVal &SelfValOut) const;
|
||||
bool instanceDeallocIsOnStack(const CheckerContext &C,
|
||||
SVal &InstanceValOut) const;
|
||||
|
||||
bool isSuperDeallocMessage(const ObjCMethodCall &M) const;
|
||||
|
||||
const ObjCImplDecl *getContainingObjCImpl(const LocationContext *LCtx) const;
|
||||
const ObjCImplDecl *getContainingObjCImpl(const StackFrame *SF) const;
|
||||
|
||||
const ObjCPropertyDecl *
|
||||
findShadowedPropertyDecl(const ObjCPropertyImplDecl *PropImpl) const;
|
||||
|
|
@ -267,7 +267,7 @@ void ObjCDeallocChecker::checkBeginFunction(
|
|||
|
||||
SymbolRef SelfSymbol = SelfVal.getAsSymbol();
|
||||
|
||||
const LocationContext *LCtx = C.getLocationContext();
|
||||
const StackFrame *SF = C.getStackFrame();
|
||||
ProgramStateRef InitialState = C.getState();
|
||||
|
||||
ProgramStateRef State = InitialState;
|
||||
|
|
@ -282,7 +282,7 @@ void ObjCDeallocChecker::checkBeginFunction(
|
|||
if (const SymbolSet *CurrSet = State->get<UnreleasedIvarMap>(SelfSymbol))
|
||||
RequiredReleases = *CurrSet;
|
||||
|
||||
for (auto *PropImpl : getContainingObjCImpl(LCtx)->property_impls()) {
|
||||
for (auto *PropImpl : getContainingObjCImpl(SF)->property_impls()) {
|
||||
ReleaseRequirement Requirement = getDeallocReleaseRequirement(PropImpl);
|
||||
if (Requirement != ReleaseRequirement::MustRelease)
|
||||
continue;
|
||||
|
|
@ -500,7 +500,7 @@ void ObjCDeallocChecker::diagnoseMissingReleases(CheckerContext &C) const {
|
|||
return;
|
||||
|
||||
const MemRegion *SelfRegion = SelfVal.castAs<loc::MemRegionVal>().getRegion();
|
||||
const LocationContext *LCtx = C.getLocationContext();
|
||||
const StackFrame *SF = C.getStackFrame();
|
||||
|
||||
ExplodedNode *ErrNode = nullptr;
|
||||
|
||||
|
|
@ -530,7 +530,7 @@ void ObjCDeallocChecker::diagnoseMissingReleases(CheckerContext &C) const {
|
|||
// Prevent an inlined call to -dealloc in a super class from warning
|
||||
// about the values the subclass's -dealloc should release.
|
||||
if (IvarDecl->getContainingInterface() !=
|
||||
cast<ObjCMethodDecl>(LCtx->getDecl())->getClassInterface())
|
||||
cast<ObjCMethodDecl>(SF->getDecl())->getClassInterface())
|
||||
continue;
|
||||
|
||||
// Prevents diagnosing multiple times for the same instance variable
|
||||
|
|
@ -604,7 +604,7 @@ void ObjCDeallocChecker::diagnoseMissingReleases(CheckerContext &C) const {
|
|||
// Make sure that after checking in the top-most frame the list of
|
||||
// tracked ivars is empty. This is intended to detect accidental leaks in
|
||||
// the UnreleasedIvarMap program state.
|
||||
assert(!LCtx->inTopFrame() || State->get<UnreleasedIvarMap>().isEmpty());
|
||||
assert(!SF->inTopFrame() || State->get<UnreleasedIvarMap>().isEmpty());
|
||||
}
|
||||
|
||||
/// Given a symbol, determine whether the symbol refers to an ivar on
|
||||
|
|
@ -628,10 +628,10 @@ ObjCDeallocChecker::findPropertyOnDeallocatingInstance(
|
|||
IvarRegion->getSuperRegion())
|
||||
return nullptr;
|
||||
|
||||
const LocationContext *LCtx = C.getLocationContext();
|
||||
const StackFrame *SF = C.getStackFrame();
|
||||
const ObjCIvarDecl *IvarDecl = IvarRegion->getDecl();
|
||||
|
||||
const ObjCImplDecl *Container = getContainingObjCImpl(LCtx);
|
||||
const ObjCImplDecl *Container = getContainingObjCImpl(SF);
|
||||
const ObjCPropertyImplDecl *PropImpl =
|
||||
Container->FindPropertyImplIvarDecl(IvarDecl->getIdentifier());
|
||||
return PropImpl;
|
||||
|
|
@ -688,7 +688,7 @@ bool ObjCDeallocChecker::diagnoseExtraRelease(SymbolRef ReleasedValue,
|
|||
isReleasedByCIFilterDealloc(PropImpl)
|
||||
);
|
||||
|
||||
const ObjCImplDecl *Container = getContainingObjCImpl(C.getLocationContext());
|
||||
const ObjCImplDecl *Container = getContainingObjCImpl(C.getStackFrame());
|
||||
OS << "The '" << *PropImpl->getPropertyIvarDecl()
|
||||
<< "' ivar in '" << *Container;
|
||||
|
||||
|
|
@ -783,10 +783,10 @@ bool ObjCDeallocChecker::isSuperDeallocMessage(
|
|||
return M.getSelector() == DeallocSel;
|
||||
}
|
||||
|
||||
/// Returns the ObjCImplDecl containing the method declaration in LCtx.
|
||||
/// Returns the ObjCImplDecl containing the method declaration in SF.
|
||||
const ObjCImplDecl *
|
||||
ObjCDeallocChecker::getContainingObjCImpl(const LocationContext *LCtx) const {
|
||||
auto *MD = cast<ObjCMethodDecl>(LCtx->getDecl());
|
||||
ObjCDeallocChecker::getContainingObjCImpl(const StackFrame *SF) const {
|
||||
auto *MD = cast<ObjCMethodDecl>(SF->getDecl());
|
||||
return cast<ObjCImplDecl>(MD->getDeclContext());
|
||||
}
|
||||
|
||||
|
|
@ -957,24 +957,24 @@ ObjCDeallocChecker::getValueReleasedByNillingOut(const ObjCMethodCall &M,
|
|||
/// 'self'.
|
||||
bool ObjCDeallocChecker::isInInstanceDealloc(const CheckerContext &C,
|
||||
SVal &SelfValOut) const {
|
||||
return isInInstanceDealloc(C, C.getLocationContext(), SelfValOut);
|
||||
return isInInstanceDealloc(C, C.getStackFrame(), SelfValOut);
|
||||
}
|
||||
|
||||
/// Returns true if LCtx is a call to -dealloc and false
|
||||
/// Returns true if SF is a call to -dealloc and false
|
||||
/// otherwise. If true, it also sets SelfValOut to the value of
|
||||
/// 'self'.
|
||||
bool ObjCDeallocChecker::isInInstanceDealloc(const CheckerContext &C,
|
||||
const LocationContext *LCtx,
|
||||
const StackFrame *SF,
|
||||
SVal &SelfValOut) const {
|
||||
auto *MD = dyn_cast<ObjCMethodDecl>(LCtx->getDecl());
|
||||
auto *MD = dyn_cast<ObjCMethodDecl>(SF->getDecl());
|
||||
if (!MD || !MD->isInstanceMethod() || MD->getSelector() != DeallocSel)
|
||||
return false;
|
||||
|
||||
const ImplicitParamDecl *SelfDecl = LCtx->getSelfDecl();
|
||||
const ImplicitParamDecl *SelfDecl = SF->getSelfDecl();
|
||||
assert(SelfDecl && "No self in -dealloc?");
|
||||
|
||||
ProgramStateRef State = C.getState();
|
||||
SelfValOut = State->getSVal(State->getRegion(SelfDecl, LCtx));
|
||||
SelfValOut = State->getSVal(State->getRegion(SelfDecl, SF));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -983,13 +983,13 @@ bool ObjCDeallocChecker::isInInstanceDealloc(const CheckerContext &C,
|
|||
/// 'self' in the frame for -dealloc.
|
||||
bool ObjCDeallocChecker::instanceDeallocIsOnStack(const CheckerContext &C,
|
||||
SVal &InstanceValOut) const {
|
||||
const LocationContext *LCtx = C.getLocationContext();
|
||||
const StackFrame *SF = C.getStackFrame();
|
||||
|
||||
while (LCtx) {
|
||||
if (isInInstanceDealloc(C, LCtx, InstanceValOut))
|
||||
while (SF) {
|
||||
if (isInInstanceDealloc(C, SF, InstanceValOut))
|
||||
return true;
|
||||
|
||||
LCtx = LCtx->getParent();
|
||||
SF = SF->getParent();
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -314,19 +314,18 @@ public:
|
|||
/// by this change. For a simple bind, this list will be the same as
|
||||
/// \p ExplicitRegions, since a bind does not affect the contents of
|
||||
/// anything accessible through the base region.
|
||||
/// \param LCtx LocationContext that is useful for getting various contextual
|
||||
/// \param SF StackFrame that is useful for getting various contextual
|
||||
/// info, like callstack, CFG etc.
|
||||
/// \param Call The opaque call triggering this invalidation. Will be 0 if the
|
||||
/// change was not triggered by a call.
|
||||
///
|
||||
/// check::RegionChanges
|
||||
ProgramStateRef
|
||||
checkRegionChanges(ProgramStateRef State,
|
||||
const InvalidatedSymbols *Invalidated,
|
||||
ArrayRef<const MemRegion *> ExplicitRegions,
|
||||
ArrayRef<const MemRegion *> Regions,
|
||||
const LocationContext *LCtx,
|
||||
const CallEvent *Call) const {
|
||||
checkRegionChanges(ProgramStateRef State,
|
||||
const InvalidatedSymbols *Invalidated,
|
||||
ArrayRef<const MemRegion *> ExplicitRegions,
|
||||
ArrayRef<const MemRegion *> Regions, const StackFrame *SF,
|
||||
const CallEvent *Call) const {
|
||||
return State;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ bool ChrootChecker::evalCall(const CallEvent &Call, CheckerContext &C) const {
|
|||
|
||||
bool ChrootChecker::evalChroot(const CallEvent &Call, CheckerContext &C) const {
|
||||
BasicValueFactory &BVF = C.getSValBuilder().getBasicValueFactory();
|
||||
const LocationContext *LCtx = C.getLocationContext();
|
||||
const StackFrame *SF = C.getStackFrame();
|
||||
ProgramStateRef State = C.getState();
|
||||
const auto *CE = cast<CallExpr>(Call.getOriginExpr());
|
||||
|
||||
|
|
@ -82,10 +82,10 @@ bool ChrootChecker::evalChroot(const CallEvent &Call, CheckerContext &C) const {
|
|||
SVal Zero = nonloc::ConcreteInt{BVF.getValue(0, IntTy)};
|
||||
SVal Minus1 = nonloc::ConcreteInt{BVF.getValue(-1, IntTy)};
|
||||
|
||||
ProgramStateRef ChrootFailed = State->BindExpr(CE, LCtx, Minus1);
|
||||
ProgramStateRef ChrootFailed = State->BindExpr(CE, SF, Minus1);
|
||||
C.addTransition(ChrootFailed->set<ChrootState>(ROOT_CHANGE_FAILED));
|
||||
|
||||
ProgramStateRef ChrootSucceeded = State->BindExpr(CE, LCtx, Zero);
|
||||
ProgramStateRef ChrootSucceeded = State->BindExpr(CE, SF, Zero);
|
||||
C.addTransition(ChrootSucceeded->set<ChrootState>(ROOT_CHANGED));
|
||||
return true;
|
||||
}
|
||||
|
|
@ -136,7 +136,7 @@ public:
|
|||
|
||||
Satisfied = true;
|
||||
PathDiagnosticLocation Pos(Call, BRC.getSourceManager(),
|
||||
N->getLocationContext());
|
||||
N->getStackFrame());
|
||||
return std::make_shared<PathDiagnosticEventPiece>(Pos, "chroot called here",
|
||||
/*addPosRange=*/true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,12 +109,10 @@ SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont);
|
|||
ProgramStateRef createContainerBegin(ProgramStateRef State,
|
||||
const MemRegion *Cont,
|
||||
ConstCFGElementRef Elem, QualType T,
|
||||
const LocationContext *LCtx,
|
||||
unsigned BlockCount);
|
||||
const StackFrame *SF, unsigned BlockCount);
|
||||
ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont,
|
||||
ConstCFGElementRef Elem, QualType T,
|
||||
const LocationContext *LCtx,
|
||||
unsigned BlockCount);
|
||||
const StackFrame *SF, unsigned BlockCount);
|
||||
ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont,
|
||||
const ContainerData &CData);
|
||||
ProgramStateRef invalidateAllIteratorPositions(ProgramStateRef State,
|
||||
|
|
@ -264,7 +262,7 @@ void ContainerModeling::handleBegin(CheckerContext &C, ConstCFGElementRef Elem,
|
|||
auto BeginSym = getContainerBegin(State, ContReg);
|
||||
if (!BeginSym) {
|
||||
State = createContainerBegin(State, ContReg, Elem, C.getASTContext().LongTy,
|
||||
C.getLocationContext(), C.blockCount());
|
||||
C.getStackFrame(), C.blockCount());
|
||||
BeginSym = getContainerBegin(State, ContReg);
|
||||
}
|
||||
State = setIteratorPosition(State, RetVal,
|
||||
|
|
@ -286,7 +284,7 @@ void ContainerModeling::handleEnd(CheckerContext &C, ConstCFGElementRef Elem,
|
|||
auto EndSym = getContainerEnd(State, ContReg);
|
||||
if (!EndSym) {
|
||||
State = createContainerEnd(State, ContReg, Elem, C.getASTContext().LongTy,
|
||||
C.getLocationContext(), C.blockCount());
|
||||
C.getStackFrame(), C.blockCount());
|
||||
EndSym = getContainerEnd(State, ContReg);
|
||||
}
|
||||
State = setIteratorPosition(State, RetVal,
|
||||
|
|
@ -330,7 +328,7 @@ void ContainerModeling::handleAssignment(CheckerContext &C, SVal Cont,
|
|||
auto &SVB = C.getSValBuilder();
|
||||
// Then generate and assign a new "end" symbol for the new container.
|
||||
auto NewEndSym =
|
||||
SymMgr.conjureSymbol(Elem, C.getLocationContext(),
|
||||
SymMgr.conjureSymbol(Elem, C.getStackFrame(),
|
||||
C.getASTContext().LongTy, C.blockCount());
|
||||
State = assumeNoOverflow(State, NewEndSym, 4);
|
||||
if (CData) {
|
||||
|
|
@ -851,7 +849,7 @@ SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont) {
|
|||
ProgramStateRef createContainerBegin(ProgramStateRef State,
|
||||
const MemRegion *Cont,
|
||||
ConstCFGElementRef Elem, QualType T,
|
||||
const LocationContext *LCtx,
|
||||
const StackFrame *SF,
|
||||
unsigned BlockCount) {
|
||||
// Only create if it does not exist
|
||||
const auto *CDataPtr = getContainerData(State, Cont);
|
||||
|
|
@ -860,7 +858,7 @@ ProgramStateRef createContainerBegin(ProgramStateRef State,
|
|||
|
||||
auto &SymMgr = State->getSymbolManager();
|
||||
const SymbolConjured *Sym =
|
||||
SymMgr.conjureSymbol(Elem, LCtx, T, BlockCount, "begin");
|
||||
SymMgr.conjureSymbol(Elem, SF, T, BlockCount, "begin");
|
||||
State = assumeNoOverflow(State, Sym, 4);
|
||||
|
||||
if (CDataPtr) {
|
||||
|
|
@ -874,8 +872,7 @@ ProgramStateRef createContainerBegin(ProgramStateRef State,
|
|||
|
||||
ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont,
|
||||
ConstCFGElementRef Elem, QualType T,
|
||||
const LocationContext *LCtx,
|
||||
unsigned BlockCount) {
|
||||
const StackFrame *SF, unsigned BlockCount) {
|
||||
// Only create if it does not exist
|
||||
const auto *CDataPtr = getContainerData(State, Cont);
|
||||
if (CDataPtr && CDataPtr->getEnd())
|
||||
|
|
@ -883,7 +880,7 @@ ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont,
|
|||
|
||||
auto &SymMgr = State->getSymbolManager();
|
||||
const SymbolConjured *Sym =
|
||||
SymMgr.conjureSymbol(Elem, LCtx, T, BlockCount, "end");
|
||||
SymMgr.conjureSymbol(Elem, SF, T, BlockCount, "end");
|
||||
State = assumeNoOverflow(State, Sym, 4);
|
||||
|
||||
if (CDataPtr) {
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ void ConversionChecker::checkPreStmt(const ImplicitCastExpr *Cast,
|
|||
return;
|
||||
|
||||
// Get Parent.
|
||||
const ParentMap &PM = C.getLocationContext()->getParentMap();
|
||||
const ParentMap &PM = C.getStackFrame()->getParentMap();
|
||||
const Stmt *Parent = PM.getParent(Cast);
|
||||
if (!Parent)
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -84,8 +84,8 @@ void DebugContainerModeling::analyzerContainerDataField(const CallExpr *CE,
|
|||
if (Data) {
|
||||
SymbolRef Field = get(Data);
|
||||
if (Field) {
|
||||
State = State->BindExpr(CE, C.getLocationContext(),
|
||||
nonloc::SymbolVal(Field));
|
||||
State =
|
||||
State->BindExpr(CE, C.getStackFrame(), nonloc::SymbolVal(Field));
|
||||
|
||||
// Progpagate interestingness from the container's data (marked
|
||||
// interesting by an `ExprInspection` debug call to the container
|
||||
|
|
@ -105,8 +105,9 @@ void DebugContainerModeling::analyzerContainerDataField(const CallExpr *CE,
|
|||
}
|
||||
|
||||
auto &BVF = C.getSValBuilder().getBasicValueFactory();
|
||||
State = State->BindExpr(CE, C.getLocationContext(),
|
||||
nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
|
||||
State =
|
||||
State->BindExpr(CE, C.getStackFrame(),
|
||||
nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
|
||||
}
|
||||
|
||||
void DebugContainerModeling::analyzerContainerBegin(const CallExpr *CE,
|
||||
|
|
|
|||
|
|
@ -85,9 +85,9 @@ void DebugIteratorModeling::analyzerIteratorDataField(const CallExpr *CE,
|
|||
SVal V = C.getSVal(CE->getArg(0));
|
||||
const auto *Pos = getIteratorPosition(State, V);
|
||||
if (Pos) {
|
||||
State = State->BindExpr(CE, C.getLocationContext(), get(Pos));
|
||||
State = State->BindExpr(CE, C.getStackFrame(), get(Pos));
|
||||
} else {
|
||||
State = State->BindExpr(CE, C.getLocationContext(), Default);
|
||||
State = State->BindExpr(CE, C.getStackFrame(), Default);
|
||||
}
|
||||
C.addTransition(State);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,8 +57,7 @@ public:
|
|||
static void AddDerefSource(raw_ostream &os,
|
||||
SmallVectorImpl<SourceRange> &Ranges,
|
||||
const Expr *Ex, const ProgramState *state,
|
||||
const LocationContext *LCtx,
|
||||
bool loadedFrom = false);
|
||||
const StackFrame *SF, bool loadedFrom = false);
|
||||
|
||||
CheckerFrontend NullDerefChecker, FixedDerefChecker, NullPointerArithmChecker;
|
||||
const DerefBugType NullBug{&NullDerefChecker, "Dereference of null pointer",
|
||||
|
|
@ -86,20 +85,18 @@ struct ValueDescStr {
|
|||
SmallVectorImpl<SourceRange> &Ranges;
|
||||
const Expr *Ex;
|
||||
const ProgramState *State;
|
||||
const LocationContext *LCtx;
|
||||
const StackFrame *SF;
|
||||
bool IsPointer;
|
||||
ConditionTruthVal IsNull;
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
void
|
||||
DereferenceChecker::AddDerefSource(raw_ostream &os,
|
||||
SmallVectorImpl<SourceRange> &Ranges,
|
||||
const Expr *Ex,
|
||||
const ProgramState *state,
|
||||
const LocationContext *LCtx,
|
||||
bool loadedFrom) {
|
||||
void DereferenceChecker::AddDerefSource(raw_ostream &os,
|
||||
SmallVectorImpl<SourceRange> &Ranges,
|
||||
const Expr *Ex,
|
||||
const ProgramState *state,
|
||||
const StackFrame *SF, bool loadedFrom) {
|
||||
Ex = Ex->IgnoreParenLValueCasts();
|
||||
switch (Ex->getStmtClass()) {
|
||||
default:
|
||||
|
|
@ -219,7 +216,7 @@ void DereferenceChecker::reportDerefBug(const DerefBugType &BT,
|
|||
Out << "Array access";
|
||||
const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(S);
|
||||
AddDerefSource(Out, Ranges, AE->getBase()->IgnoreParenCasts(), State.get(),
|
||||
N->getLocationContext());
|
||||
N->getStackFrame());
|
||||
Out << " results in " << BT.getArrayMsg();
|
||||
break;
|
||||
}
|
||||
|
|
@ -227,7 +224,7 @@ void DereferenceChecker::reportDerefBug(const DerefBugType &BT,
|
|||
Out << "Array access";
|
||||
const ArraySectionExpr *AE = cast<ArraySectionExpr>(S);
|
||||
AddDerefSource(Out, Ranges, AE->getBase()->IgnoreParenCasts(), State.get(),
|
||||
N->getLocationContext());
|
||||
N->getStackFrame());
|
||||
Out << " results in " << BT.getArrayMsg();
|
||||
break;
|
||||
}
|
||||
|
|
@ -235,7 +232,7 @@ void DereferenceChecker::reportDerefBug(const DerefBugType &BT,
|
|||
Out << BT.getDescription();
|
||||
const UnaryOperator *U = cast<UnaryOperator>(S);
|
||||
AddDerefSource(Out, Ranges, U->getSubExpr()->IgnoreParens(), State.get(),
|
||||
N->getLocationContext(), true);
|
||||
N->getStackFrame(), true);
|
||||
break;
|
||||
}
|
||||
case Stmt::MemberExprClass: {
|
||||
|
|
@ -244,7 +241,7 @@ void DereferenceChecker::reportDerefBug(const DerefBugType &BT,
|
|||
Out << "Access to field '" << M->getMemberNameInfo() << "' results in "
|
||||
<< BT.getFieldMsg();
|
||||
AddDerefSource(Out, Ranges, M->getBase()->IgnoreParenCasts(), State.get(),
|
||||
N->getLocationContext(), true);
|
||||
N->getStackFrame(), true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -253,7 +250,7 @@ void DereferenceChecker::reportDerefBug(const DerefBugType &BT,
|
|||
Out << "Access to instance variable '" << *IV->getDecl() << "' results in "
|
||||
<< BT.getFieldMsg();
|
||||
AddDerefSource(Out, Ranges, IV->getBase()->IgnoreParenCasts(), State.get(),
|
||||
N->getLocationContext(), true);
|
||||
N->getStackFrame(), true);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
@ -407,7 +404,7 @@ template <> struct format_provider<ValueDescStr> {
|
|||
<< ValueStr[V.IsPointer][V.IsNull.isConstrainedTrue()
|
||||
? 0
|
||||
: (V.IsNull.isConstrainedFalse() ? 1 : 2)];
|
||||
DereferenceChecker::AddDerefSource(Stream, V.Ranges, V.Ex, V.State, V.LCtx,
|
||||
DereferenceChecker::AddDerefSource(Stream, V.Ranges, V.Ex, V.State, V.SF,
|
||||
false);
|
||||
}
|
||||
};
|
||||
|
|
@ -462,10 +459,10 @@ void DereferenceChecker::checkPreStmt(const BinaryOperator *Op,
|
|||
const char *OpcodeStr =
|
||||
Op->getOpcode() == BO_Add ? "Addition" : "Subtraction";
|
||||
const char *ResultStr = IsConstrained ? "results" : "may result";
|
||||
ValueDescStr DerefArg1{
|
||||
Ranges, E1, State.get(), C.getLocationContext(), T1IsPointer, V1IsNull};
|
||||
ValueDescStr DerefArg2{
|
||||
Ranges, E2, State.get(), C.getLocationContext(), T2IsPointer, V2IsNull};
|
||||
ValueDescStr DerefArg1{Ranges, E1, State.get(), C.getStackFrame(),
|
||||
T1IsPointer, V1IsNull};
|
||||
ValueDescStr DerefArg2{Ranges, E2, State.get(), C.getStackFrame(),
|
||||
T2IsPointer, V2IsNull};
|
||||
std::string Msg =
|
||||
llvm::formatv("{0} of a {1} and a {2} {3} in undefined behavior",
|
||||
OpcodeStr, DerefArg1, DerefArg2, ResultStr);
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ class DirectIvarAssignment :
|
|||
const ObjCInterfaceDecl *InterfD;
|
||||
BugReporter &BR;
|
||||
const CheckerBase *Checker;
|
||||
LocationOrAnalysisDeclContext DCtx;
|
||||
StackFrameOrAnalysisDeclContext DCtx;
|
||||
|
||||
public:
|
||||
MethodCrawler(const IvarToPropertyMapTy &InMap, const ObjCMethodDecl *InMD,
|
||||
|
|
|
|||
|
|
@ -129,8 +129,7 @@ PathDiagnosticPieceRef DynamicTypeChecker::DynamicTypeBugVisitor::VisitNode(
|
|||
}
|
||||
|
||||
// Generate the extra diagnostic.
|
||||
PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
|
||||
N->getLocationContext());
|
||||
PathDiagnosticLocation Pos(S, BRC.getSourceManager(), N->getStackFrame());
|
||||
return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(), true);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ RuntimeType inferReceiverType(const ObjCMethodCall &Message,
|
|||
return {cast<ObjCObjectType>(DTI.getType()), !DTI.canBeASubClass()};
|
||||
}
|
||||
|
||||
SVal SelfSVal = State->getSelfSVal(C.getLocationContext());
|
||||
SVal SelfSVal = State->getSelfSVal(C.getStackFrame());
|
||||
|
||||
// Another way we can guess what is in Class object, is when it is a
|
||||
// 'self' variable of the current class method.
|
||||
|
|
@ -369,7 +369,7 @@ void DynamicTypePropagation::checkPostCall(const CallEvent &Call,
|
|||
if (const MemRegion *Target = Ctor->getCXXThisVal().getAsRegion()) {
|
||||
// We just finished a base constructor. Now we can use the subclass's
|
||||
// type when resolving virtual calls.
|
||||
const LocationContext *LCtx = C.getLocationContext();
|
||||
const StackFrame *SF = C.getStackFrame();
|
||||
|
||||
// FIXME: In C++17 classes with non-virtual bases may be treated as
|
||||
// aggregates, and in such case no top-frame constructor will be called.
|
||||
|
|
@ -378,10 +378,10 @@ void DynamicTypePropagation::checkPostCall(const CallEvent &Call,
|
|||
// trigger-statement (InitListExpr or CXXParenListInitExpr in this case)
|
||||
// available in this callback, ideally as part of CallEvent.
|
||||
if (isa_and_nonnull<InitListExpr, CXXParenListInitExpr>(
|
||||
LCtx->getParentMap().getParent(Ctor->getOriginExpr())))
|
||||
SF->getParentMap().getParent(Ctor->getOriginExpr())))
|
||||
return;
|
||||
|
||||
recordFixedType(Target, cast<CXXConstructorDecl>(LCtx->getDecl()), C);
|
||||
recordFixedType(Target, cast<CXXConstructorDecl>(SF->getDecl()), C);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -1090,8 +1090,7 @@ PathDiagnosticPieceRef DynamicTypePropagation::GenericsBugVisitor::VisitNode(
|
|||
}
|
||||
|
||||
// Generate the extra diagnostic.
|
||||
PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
|
||||
N->getLocationContext());
|
||||
PathDiagnosticLocation Pos(S, BRC.getSourceManager(), N->getStackFrame());
|
||||
return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(), true);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,8 +40,8 @@ public:
|
|||
checkRegionChanges(ProgramStateRef State,
|
||||
const InvalidatedSymbols *Invalidated,
|
||||
ArrayRef<const MemRegion *> ExplicitRegions,
|
||||
ArrayRef<const MemRegion *> Regions,
|
||||
const LocationContext *LCtx, const CallEvent *Call) const;
|
||||
ArrayRef<const MemRegion *> Regions, const StackFrame *SF,
|
||||
const CallEvent *Call) const;
|
||||
|
||||
/// Indicates if a read (load) of \c errno is allowed in a non-condition part
|
||||
/// of \c if, \c switch, loop and conditional statements when the errno
|
||||
|
|
@ -217,7 +217,7 @@ void ErrnoChecker::checkPreCall(const CallEvent &Call,
|
|||
ProgramStateRef ErrnoChecker::checkRegionChanges(
|
||||
ProgramStateRef State, const InvalidatedSymbols *Invalidated,
|
||||
ArrayRef<const MemRegion *> ExplicitRegions,
|
||||
ArrayRef<const MemRegion *> Regions, const LocationContext *LCtx,
|
||||
ArrayRef<const MemRegion *> Regions, const StackFrame *SF,
|
||||
const CallEvent *Call) const {
|
||||
std::optional<ento::Loc> ErrnoLoc = getErrnoLoc(State);
|
||||
if (!ErrnoLoc)
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ void ErrnoModeling::checkBeginFunction(CheckerContext &C) const {
|
|||
if (ErrnoDecl) {
|
||||
// There is an external 'errno' variable, so we can simply use the memory
|
||||
// region that's associated with it.
|
||||
ErrnoR = State->getRegion(ErrnoDecl, C.getLocationContext());
|
||||
ErrnoR = State->getRegion(ErrnoDecl, C.getStackFrame());
|
||||
assert(ErrnoR && "Memory region should exist for the 'errno' variable.");
|
||||
} else {
|
||||
// There is no 'errno' variable, so create a new symbolic memory region
|
||||
|
|
@ -122,7 +122,7 @@ void ErrnoModeling::checkBeginFunction(CheckerContext &C) const {
|
|||
// of the data member `ErrnoDecl` of the singleton `ErrnoModeling` checker
|
||||
// object.
|
||||
const SymbolConjured *Sym = SVB.conjureSymbol(
|
||||
C.getCFGElementRef(), C.getLocationContext(),
|
||||
C.getCFGElementRef(), C.getStackFrame(),
|
||||
ACtx.getLValueReferenceType(ACtx.IntTy), C.blockCount(), &ErrnoDecl);
|
||||
|
||||
// The symbolic region is untyped, create a typed sub-region in it.
|
||||
|
|
@ -148,7 +148,7 @@ bool ErrnoModeling::evalCall(const CallEvent &Call, CheckerContext &C) const {
|
|||
if (!ErrnoR)
|
||||
return false;
|
||||
|
||||
State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
|
||||
State = State->BindExpr(Call.getOriginExpr(), C.getStackFrame(),
|
||||
loc::MemRegionVal{ErrnoR});
|
||||
C.addTransition(State);
|
||||
return true;
|
||||
|
|
@ -176,15 +176,14 @@ std::optional<SVal> getErrnoValue(ProgramStateRef State) {
|
|||
return State->getSVal(ErrnoR, IntTy);
|
||||
}
|
||||
|
||||
ProgramStateRef setErrnoValue(ProgramStateRef State,
|
||||
const LocationContext *LCtx, SVal Value,
|
||||
ErrnoCheckState EState) {
|
||||
ProgramStateRef setErrnoValue(ProgramStateRef State, const StackFrame *SF,
|
||||
SVal Value, ErrnoCheckState EState) {
|
||||
const MemRegion *ErrnoR = State->get<ErrnoRegion>();
|
||||
if (!ErrnoR)
|
||||
return State;
|
||||
// First set the errno value, the old state is still available at 'checkBind'
|
||||
// or 'checkLocation' for errno value.
|
||||
State = State->bindLoc(loc::MemRegionVal{ErrnoR}, Value, LCtx);
|
||||
State = State->bindLoc(loc::MemRegionVal{ErrnoR}, Value, SF);
|
||||
return State->set<ErrnoState>(EState);
|
||||
}
|
||||
|
||||
|
|
@ -196,7 +195,7 @@ ProgramStateRef setErrnoValue(ProgramStateRef State, CheckerContext &C,
|
|||
State = State->bindLoc(
|
||||
loc::MemRegionVal{ErrnoR},
|
||||
C.getSValBuilder().makeIntVal(Value, C.getASTContext().IntTy),
|
||||
C.getLocationContext());
|
||||
C.getStackFrame());
|
||||
return State->set<ErrnoState>(EState);
|
||||
}
|
||||
|
||||
|
|
@ -249,7 +248,7 @@ ProgramStateRef setErrnoForStdFailure(ProgramStateRef State, CheckerContext &C,
|
|||
State = State->assume(Cond, true);
|
||||
if (!State)
|
||||
return nullptr;
|
||||
return setErrnoValue(State, C.getLocationContext(), ErrnoSym, Irrelevant);
|
||||
return setErrnoValue(State, C.getStackFrame(), ErrnoSym, Irrelevant);
|
||||
}
|
||||
|
||||
ProgramStateRef setErrnoStdMustBeChecked(ProgramStateRef State,
|
||||
|
|
@ -259,7 +258,7 @@ ProgramStateRef setErrnoStdMustBeChecked(ProgramStateRef State,
|
|||
if (!ErrnoR)
|
||||
return State;
|
||||
State = State->invalidateRegions(ErrnoR, Elem, C.blockCount(),
|
||||
C.getLocationContext(), false);
|
||||
C.getStackFrame(), false);
|
||||
if (!State)
|
||||
return nullptr;
|
||||
return setErrnoState(State, MustBeChecked);
|
||||
|
|
|
|||
|
|
@ -56,9 +56,8 @@ std::optional<Loc> getErrnoLoc(ProgramStateRef State);
|
|||
|
||||
/// Set value of 'errno' to any SVal, if possible.
|
||||
/// The errno check state is set always when the 'errno' value is set.
|
||||
ProgramStateRef setErrnoValue(ProgramStateRef State,
|
||||
const LocationContext *LCtx, SVal Value,
|
||||
ErrnoCheckState EState);
|
||||
ProgramStateRef setErrnoValue(ProgramStateRef State, const StackFrame *SF,
|
||||
SVal Value, ErrnoCheckState EState);
|
||||
|
||||
/// Set value of 'errno' to a concrete (signed) integer, if possible.
|
||||
/// The errno check state is set always when the 'errno' value is set.
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ private:
|
|||
|
||||
void ErrnoTesterChecker::evalSetErrno(CheckerContext &C,
|
||||
const CallEvent &Call) {
|
||||
C.addTransition(setErrnoValue(C.getState(), C.getLocationContext(),
|
||||
C.addTransition(setErrnoValue(C.getState(), C.getStackFrame(),
|
||||
Call.getArgSVal(0), Irrelevant));
|
||||
}
|
||||
|
||||
|
|
@ -96,8 +96,7 @@ void ErrnoTesterChecker::evalGetErrno(CheckerContext &C,
|
|||
|
||||
std::optional<SVal> ErrnoVal = getErrnoValue(State);
|
||||
assert(ErrnoVal && "Errno value should be available.");
|
||||
State =
|
||||
State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), *ErrnoVal);
|
||||
State = State->BindExpr(Call.getOriginExpr(), C.getStackFrame(), *ErrnoVal);
|
||||
|
||||
C.addTransition(State);
|
||||
}
|
||||
|
|
@ -108,11 +107,11 @@ void ErrnoTesterChecker::evalSetErrnoIfError(CheckerContext &C,
|
|||
SValBuilder &SVB = C.getSValBuilder();
|
||||
|
||||
ProgramStateRef StateSuccess = State->BindExpr(
|
||||
Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(0, true));
|
||||
Call.getOriginExpr(), C.getStackFrame(), SVB.makeIntVal(0, true));
|
||||
StateSuccess = setErrnoState(StateSuccess, MustNotBeChecked);
|
||||
|
||||
ProgramStateRef StateFailure = State->BindExpr(
|
||||
Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(1, true));
|
||||
Call.getOriginExpr(), C.getStackFrame(), SVB.makeIntVal(1, true));
|
||||
StateFailure = setErrnoValue(StateFailure, C, 11, Irrelevant);
|
||||
|
||||
C.addTransition(StateSuccess);
|
||||
|
|
@ -125,16 +124,16 @@ void ErrnoTesterChecker::evalSetErrnoIfErrorRange(CheckerContext &C,
|
|||
SValBuilder &SVB = C.getSValBuilder();
|
||||
|
||||
ProgramStateRef StateSuccess = State->BindExpr(
|
||||
Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(0, true));
|
||||
Call.getOriginExpr(), C.getStackFrame(), SVB.makeIntVal(0, true));
|
||||
StateSuccess = setErrnoState(StateSuccess, MustNotBeChecked);
|
||||
|
||||
ProgramStateRef StateFailure = State->BindExpr(
|
||||
Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(1, true));
|
||||
Call.getOriginExpr(), C.getStackFrame(), SVB.makeIntVal(1, true));
|
||||
DefinedOrUnknownSVal ErrnoVal = SVB.conjureSymbolVal(Call, C.blockCount());
|
||||
StateFailure = StateFailure->assume(ErrnoVal, true);
|
||||
assert(StateFailure && "Failed to assume on an initial value.");
|
||||
StateFailure =
|
||||
setErrnoValue(StateFailure, C.getLocationContext(), ErrnoVal, Irrelevant);
|
||||
setErrnoValue(StateFailure, C.getStackFrame(), ErrnoVal, Irrelevant);
|
||||
|
||||
C.addTransition(StateSuccess);
|
||||
C.addTransition(StateFailure);
|
||||
|
|
@ -146,15 +145,15 @@ void ErrnoTesterChecker::evalSetErrnoCheckState(CheckerContext &C,
|
|||
SValBuilder &SVB = C.getSValBuilder();
|
||||
|
||||
ProgramStateRef StateSuccess = State->BindExpr(
|
||||
Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(0, true));
|
||||
Call.getOriginExpr(), C.getStackFrame(), SVB.makeIntVal(0, true));
|
||||
StateSuccess = setErrnoState(StateSuccess, MustNotBeChecked);
|
||||
|
||||
ProgramStateRef StateFailure1 = State->BindExpr(
|
||||
Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(1, true));
|
||||
Call.getOriginExpr(), C.getStackFrame(), SVB.makeIntVal(1, true));
|
||||
StateFailure1 = setErrnoValue(StateFailure1, C, 1, Irrelevant);
|
||||
|
||||
ProgramStateRef StateFailure2 = State->BindExpr(
|
||||
Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(2, true));
|
||||
Call.getOriginExpr(), C.getStackFrame(), SVB.makeIntVal(2, true));
|
||||
StateFailure2 = setErrnoValue(StateFailure2, C, 2, MustBeChecked);
|
||||
|
||||
C.addTransition(StateSuccess,
|
||||
|
|
|
|||
|
|
@ -136,11 +136,11 @@ static const char *getArgumentValueString(const CallExpr *CE,
|
|||
return "Missing assertion argument";
|
||||
|
||||
ExplodedNode *N = C.getPredecessor();
|
||||
const LocationContext *LC = N->getLocationContext();
|
||||
const StackFrame *SF = N->getStackFrame();
|
||||
ProgramStateRef State = N->getState();
|
||||
|
||||
const Expr *Assertion = CE->getArg(0);
|
||||
SVal AssertionVal = State->getSVal(Assertion, LC);
|
||||
SVal AssertionVal = State->getSVal(Assertion, SF);
|
||||
|
||||
if (AssertionVal.isUndef())
|
||||
return "UNDEFINED";
|
||||
|
|
@ -210,11 +210,11 @@ const MemRegion *ExprInspectionChecker::getArgRegion(const CallExpr *CE,
|
|||
|
||||
void ExprInspectionChecker::analyzerEval(const CallExpr *CE,
|
||||
CheckerContext &C) const {
|
||||
const LocationContext *LC = C.getPredecessor()->getLocationContext();
|
||||
const StackFrame *SF = C.getPredecessor()->getStackFrame();
|
||||
|
||||
// A specific instantiation of an inlined function may have more constrained
|
||||
// values than can generally be assumed. Skip the check.
|
||||
if (LC->getStackFrame()->getParent() != nullptr)
|
||||
if (SF->getParent() != nullptr)
|
||||
return;
|
||||
|
||||
reportBug(getArgumentValueString(CE, C), C);
|
||||
|
|
@ -237,14 +237,14 @@ void ExprInspectionChecker::analyzerNumTimesReached(const CallExpr *CE,
|
|||
|
||||
void ExprInspectionChecker::analyzerCheckInlined(const CallExpr *CE,
|
||||
CheckerContext &C) const {
|
||||
const LocationContext *LC = C.getPredecessor()->getLocationContext();
|
||||
const StackFrame *SF = C.getPredecessor()->getStackFrame();
|
||||
|
||||
// An inlined function could conceivably also be analyzed as a top-level
|
||||
// function. We ignore this case and only emit a message (TRUE or FALSE)
|
||||
// when we are analyzing it as an inlined function. This means that
|
||||
// clang_analyzer_checkInlined(true) should always print TRUE, but
|
||||
// clang_analyzer_checkInlined(false) should never actually print anything.
|
||||
if (LC->getStackFrame()->getParent() == nullptr)
|
||||
if (SF->getParent() == nullptr)
|
||||
return;
|
||||
|
||||
reportBug(getArgumentValueString(CE, C), C);
|
||||
|
|
@ -329,7 +329,7 @@ void ExprInspectionChecker::analyzerGetExtent(const CallExpr *CE,
|
|||
ProgramStateRef State = C.getState();
|
||||
SVal Size = getDynamicExtentWithOffset(State, C.getSVal(Arg));
|
||||
|
||||
State = State->BindExpr(CE, C.getLocationContext(), Size);
|
||||
State = State->BindExpr(CE, C.getStackFrame(), Size);
|
||||
C.addTransition(State);
|
||||
}
|
||||
|
||||
|
|
@ -430,8 +430,8 @@ void ExprInspectionChecker::analyzerHashDump(const CallExpr *CE,
|
|||
const LangOptions &Opts = C.getLangOpts();
|
||||
const SourceManager &SM = C.getSourceManager();
|
||||
FullSourceLoc FL(CE->getArg(0)->getBeginLoc(), SM);
|
||||
std::string HashContent = getIssueString(
|
||||
FL, getName(), "Category", C.getLocationContext()->getDecl(), Opts);
|
||||
std::string HashContent = getIssueString(FL, getName(), "Category",
|
||||
C.getStackFrame()->getDecl(), Opts);
|
||||
|
||||
reportBug(HashContent, C);
|
||||
}
|
||||
|
|
@ -551,7 +551,7 @@ void ExprInspectionChecker::analyzerIsTainted(const CallExpr *CE,
|
|||
return;
|
||||
}
|
||||
const bool IsTainted =
|
||||
taint::isTainted(C.getState(), CE->getArg(0), C.getLocationContext());
|
||||
taint::isTainted(C.getState(), CE->getArg(0), C.getStackFrame());
|
||||
reportBug(IsTainted ? "YES" : "NO", C);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -656,12 +656,12 @@ void FuchsiaHandleChecker::reportBug(SymbolRef Sym, ExplodedNode *ErrorNode,
|
|||
const Stmt *S = AcquireNode->getStmtForDiagnostics();
|
||||
assert(S && "Statement cannot be null.");
|
||||
PathDiagnosticLocation LocUsedForUniqueing =
|
||||
PathDiagnosticLocation::createBegin(
|
||||
S, C.getSourceManager(), AcquireNode->getLocationContext());
|
||||
PathDiagnosticLocation::createBegin(S, C.getSourceManager(),
|
||||
AcquireNode->getStackFrame());
|
||||
|
||||
R = std::make_unique<PathSensitiveBugReport>(
|
||||
Type, Msg, ErrorNode, LocUsedForUniqueing,
|
||||
AcquireNode->getLocationContext()->getDecl());
|
||||
AcquireNode->getStackFrame()->getDecl());
|
||||
}
|
||||
}
|
||||
if (!R)
|
||||
|
|
|
|||
|
|
@ -149,12 +149,12 @@ bool isTaintedOrPointsToTainted(ProgramStateRef State, SVal ExprSVal) {
|
|||
const NoteTag *taintOriginTrackerTag(CheckerContext &C,
|
||||
std::vector<SymbolRef> TaintedSymbols,
|
||||
std::vector<ArgIdxTy> TaintedArgs,
|
||||
const LocationContext *CallLocation) {
|
||||
const StackFrame *CallSF) {
|
||||
return C.getNoteTag([TaintedSymbols = std::move(TaintedSymbols),
|
||||
TaintedArgs = std::move(TaintedArgs), CallLocation](
|
||||
PathSensitiveBugReport &BR) -> std::string {
|
||||
TaintedArgs = std::move(TaintedArgs),
|
||||
CallSF](PathSensitiveBugReport &BR) -> std::string {
|
||||
// We give diagnostics only for taint related reports
|
||||
if (!BR.isInteresting(CallLocation) ||
|
||||
if (!BR.isInteresting(CallSF) ||
|
||||
BR.getBugType().getCategory() != categories::TaintedData) {
|
||||
return "";
|
||||
}
|
||||
|
|
@ -177,11 +177,11 @@ const NoteTag *taintOriginTrackerTag(CheckerContext &C,
|
|||
/// when the return value, or the outgoing parameters are tainted.
|
||||
const NoteTag *taintPropagationExplainerTag(
|
||||
CheckerContext &C, std::vector<SymbolRef> TaintedSymbols,
|
||||
std::vector<ArgIdxTy> TaintedArgs, const LocationContext *CallLocation) {
|
||||
std::vector<ArgIdxTy> TaintedArgs, const StackFrame *CallSF) {
|
||||
assert(TaintedSymbols.size() == TaintedArgs.size());
|
||||
return C.getNoteTag([TaintedSymbols = std::move(TaintedSymbols),
|
||||
TaintedArgs = std::move(TaintedArgs), CallLocation](
|
||||
PathSensitiveBugReport &BR) -> std::string {
|
||||
TaintedArgs = std::move(TaintedArgs),
|
||||
CallSF](PathSensitiveBugReport &BR) -> std::string {
|
||||
SmallString<256> Msg;
|
||||
llvm::raw_svector_ostream Out(Msg);
|
||||
// We give diagnostics only for taint related reports
|
||||
|
|
@ -192,7 +192,7 @@ const NoteTag *taintPropagationExplainerTag(
|
|||
int nofTaintedArgs = 0;
|
||||
for (auto [Idx, Sym] : llvm::enumerate(TaintedSymbols)) {
|
||||
if (BR.isInteresting(Sym)) {
|
||||
BR.markInteresting(CallLocation);
|
||||
BR.markInteresting(CallSF);
|
||||
if (TaintedArgs[Idx] != ReturnValueIndex) {
|
||||
LLVM_DEBUG(llvm::dbgs() << "Taint Propagated to argument "
|
||||
<< TaintedArgs[Idx] + 1 << "\n");
|
||||
|
|
@ -471,7 +471,7 @@ template <> struct ScalarEnumerationTraits<TaintConfiguration::VariadicType> {
|
|||
/// to the call post-visit. The values are signed integers, which are either
|
||||
/// ReturnValueIndex, or indexes of the pointer/reference argument, which
|
||||
/// points to data, which should be tainted on return.
|
||||
REGISTER_MAP_WITH_PROGRAMSTATE(TaintArgsOnPostVisit, const LocationContext *,
|
||||
REGISTER_MAP_WITH_PROGRAMSTATE(TaintArgsOnPostVisit, const StackFrame *,
|
||||
ImmutableSet<ArgIdxTy>)
|
||||
REGISTER_SET_FACTORY_WITH_PROGRAMSTATE(ArgIdxFactory, ArgIdxTy)
|
||||
|
||||
|
|
@ -847,7 +847,7 @@ void GenericTaintChecker::checkBeginFunction(CheckerContext &C) const {
|
|||
.ShouldAssumeControlledEnvironment)
|
||||
return;
|
||||
|
||||
const auto *FD = dyn_cast<FunctionDecl>(C.getLocationContext()->getDecl());
|
||||
const auto *FD = dyn_cast<FunctionDecl>(C.getStackFrame()->getDecl());
|
||||
if (!FD || !FD->isMain() || FD->param_size() < 2)
|
||||
return;
|
||||
|
||||
|
|
@ -859,7 +859,7 @@ void GenericTaintChecker::checkBeginFunction(CheckerContext &C) const {
|
|||
ProgramStateRef State = C.getState();
|
||||
|
||||
const MemRegion *ArgcReg =
|
||||
State->getRegion(FD->parameters()[0], C.getLocationContext());
|
||||
State->getRegion(FD->parameters()[0], C.getStackFrame());
|
||||
SVal ArgcSVal = State->getSVal(ArgcReg);
|
||||
State = addTaint(State, ArgcSVal);
|
||||
StringRef ArgcName = FD->parameters()[0]->getName();
|
||||
|
|
@ -872,7 +872,7 @@ void GenericTaintChecker::checkBeginFunction(CheckerContext &C) const {
|
|||
}
|
||||
|
||||
const MemRegion *ArgvReg =
|
||||
State->getRegion(FD->parameters()[1], C.getLocationContext());
|
||||
State->getRegion(FD->parameters()[1], C.getStackFrame());
|
||||
SVal ArgvSVal = State->getSVal(ArgvReg);
|
||||
State = addTaint(State, ArgvSVal);
|
||||
StringRef ArgvName = FD->parameters()[1]->getName();
|
||||
|
|
@ -884,7 +884,7 @@ void GenericTaintChecker::checkBeginFunction(CheckerContext &C) const {
|
|||
return;
|
||||
if (HaveEnvp) {
|
||||
const MemRegion *EnvPReg =
|
||||
State->getRegion(FD->parameters()[2], C.getLocationContext());
|
||||
State->getRegion(FD->parameters()[2], C.getStackFrame());
|
||||
EnvpSVal = State->getSVal(EnvPReg);
|
||||
EnvpName = FD->parameters()[2]->getName();
|
||||
State = addTaint(State, EnvpSVal);
|
||||
|
|
|
|||
|
|
@ -309,8 +309,7 @@ PathDiagnosticPieceRef InnerPointerChecker::InnerPointerBRVisitor::VisitNode(
|
|||
SmallString<256> Buf;
|
||||
llvm::raw_svector_ostream OS(Buf);
|
||||
OS << "Pointer to inner buffer of '" << ObjTy << "' obtained here";
|
||||
PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
|
||||
N->getLocationContext());
|
||||
PathDiagnosticLocation Pos(S, BRC.getSourceManager(), N->getStackFrame());
|
||||
return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(), true);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ void InvalidatedIteratorChecker::checkPreStmt(const UnaryOperator *UO,
|
|||
|
||||
ProgramStateRef State = C.getState();
|
||||
UnaryOperatorKind OK = UO->getOpcode();
|
||||
SVal SubVal = State->getSVal(UO->getSubExpr(), C.getLocationContext());
|
||||
SVal SubVal = State->getSVal(UO->getSubExpr(), C.getStackFrame());
|
||||
|
||||
if (isAccessOperator(OK)) {
|
||||
verifyAccess(C, SubVal);
|
||||
|
|
@ -85,7 +85,7 @@ void InvalidatedIteratorChecker::checkPreStmt(const BinaryOperator *BO,
|
|||
CheckerContext &C) const {
|
||||
ProgramStateRef State = C.getState();
|
||||
BinaryOperatorKind OK = BO->getOpcode();
|
||||
SVal LVal = State->getSVal(BO->getLHS(), C.getLocationContext());
|
||||
SVal LVal = State->getSVal(BO->getLHS(), C.getStackFrame());
|
||||
|
||||
if (isAccessOperator(OK)) {
|
||||
verifyAccess(C, LVal);
|
||||
|
|
@ -95,7 +95,7 @@ void InvalidatedIteratorChecker::checkPreStmt(const BinaryOperator *BO,
|
|||
void InvalidatedIteratorChecker::checkPreStmt(const ArraySubscriptExpr *ASE,
|
||||
CheckerContext &C) const {
|
||||
ProgramStateRef State = C.getState();
|
||||
SVal LVal = State->getSVal(ASE->getLHS(), C.getLocationContext());
|
||||
SVal LVal = State->getSVal(ASE->getLHS(), C.getStackFrame());
|
||||
verifyAccess(C, LVal);
|
||||
}
|
||||
|
||||
|
|
@ -105,7 +105,7 @@ void InvalidatedIteratorChecker::checkPreStmt(const MemberExpr *ME,
|
|||
return;
|
||||
|
||||
ProgramStateRef State = C.getState();
|
||||
SVal BaseVal = State->getSVal(ME->getBase(), C.getLocationContext());
|
||||
SVal BaseVal = State->getSVal(ME->getBase(), C.getStackFrame());
|
||||
verifyAccess(C, BaseVal);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -209,13 +209,13 @@ ProgramStateRef setIteratorPosition(ProgramStateRef State, SVal Val,
|
|||
ProgramStateRef createIteratorPosition(ProgramStateRef State, SVal Val,
|
||||
const MemRegion *Cont,
|
||||
ConstCFGElementRef Elem,
|
||||
const LocationContext *LCtx,
|
||||
const StackFrame *SF,
|
||||
unsigned blockCount) {
|
||||
auto &StateMgr = State->getStateManager();
|
||||
auto &SymMgr = StateMgr.getSymbolManager();
|
||||
auto &ACtx = StateMgr.getContext();
|
||||
|
||||
auto *Sym = SymMgr.conjureSymbol(Elem, LCtx, ACtx.LongTy, blockCount);
|
||||
auto *Sym = SymMgr.conjureSymbol(Elem, SF, ACtx.LongTy, blockCount);
|
||||
State = assumeNoOverflow(State, Sym, 4);
|
||||
return setIteratorPosition(State, Val,
|
||||
IteratorPosition::getPosition(Cont, Sym));
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ ProgramStateRef setIteratorPosition(ProgramStateRef State, SVal Val,
|
|||
ProgramStateRef createIteratorPosition(ProgramStateRef State, SVal Val,
|
||||
const MemRegion *Cont,
|
||||
ConstCFGElementRef Elem,
|
||||
const LocationContext *LCtx,
|
||||
const StackFrame *SF,
|
||||
unsigned blockCount);
|
||||
ProgramStateRef advancePosition(ProgramStateRef State, SVal Iter,
|
||||
OverloadedOperatorKind Op, SVal Distance);
|
||||
|
|
|
|||
|
|
@ -268,11 +268,11 @@ void IteratorModeling::checkPostStmt(const BinaryOperator *BO,
|
|||
const BinaryOperatorKind OK = BO->getOpcode();
|
||||
const Expr *const LHS = BO->getLHS();
|
||||
const Expr *const RHS = BO->getRHS();
|
||||
const SVal LVal = State->getSVal(LHS, C.getLocationContext());
|
||||
const SVal RVal = State->getSVal(RHS, C.getLocationContext());
|
||||
const SVal LVal = State->getSVal(LHS, C.getStackFrame());
|
||||
const SVal RVal = State->getSVal(RHS, C.getStackFrame());
|
||||
|
||||
if (isSimpleComparisonOperator(BO->getOpcode())) {
|
||||
SVal Result = State->getSVal(BO, C.getLocationContext());
|
||||
SVal Result = State->getSVal(BO, C.getStackFrame());
|
||||
handleComparison(C, BO, C.getCFGElementRef(), Result, LVal, RVal,
|
||||
BinaryOperator::getOverloadedOperator(OK));
|
||||
} else if (isRandomIncrOrDecrOperator(OK)) {
|
||||
|
|
@ -472,7 +472,7 @@ void IteratorModeling::handleComparison(CheckerContext &C, const Expr *CE,
|
|||
SymbolRef Sym;
|
||||
if (!LPos || !RPos) {
|
||||
auto &SymMgr = C.getSymbolManager();
|
||||
Sym = SymMgr.conjureSymbol(Elem, C.getLocationContext(),
|
||||
Sym = SymMgr.conjureSymbol(Elem, C.getStackFrame(),
|
||||
C.getASTContext().LongTy, C.blockCount());
|
||||
State = assumeNoOverflow(State, Sym, 4);
|
||||
}
|
||||
|
|
@ -497,10 +497,10 @@ void IteratorModeling::handleComparison(CheckerContext &C, const Expr *CE,
|
|||
// instead.
|
||||
if (RetVal.isUnknown()) {
|
||||
auto &SymMgr = C.getSymbolManager();
|
||||
auto *LCtx = C.getLocationContext();
|
||||
auto *SF = C.getStackFrame();
|
||||
RetVal = nonloc::SymbolVal(SymMgr.conjureSymbol(
|
||||
Elem, LCtx, C.getASTContext().BoolTy, C.blockCount()));
|
||||
State = State->BindExpr(CE, LCtx, RetVal);
|
||||
Elem, SF, C.getASTContext().BoolTy, C.blockCount()));
|
||||
State = State->BindExpr(CE, SF, RetVal);
|
||||
}
|
||||
|
||||
processComparison(C, State, LPos->getOffset(), RPos->getOffset(), RetVal, Op);
|
||||
|
|
@ -641,7 +641,7 @@ void IteratorModeling::handlePtrIncrOrDecr(CheckerContext &C,
|
|||
QualType ElementType = PtrType->getPointeeType();
|
||||
|
||||
ProgramStateRef State = C.getState();
|
||||
SVal OldVal = State->getSVal(Iterator, C.getLocationContext());
|
||||
SVal OldVal = State->getSVal(Iterator, C.getStackFrame());
|
||||
|
||||
const IteratorPosition *OldPos = getIteratorPosition(State, OldVal);
|
||||
if (!OldPos)
|
||||
|
|
@ -694,9 +694,8 @@ void IteratorModeling::assignToContainer(CheckerContext &C,
|
|||
Cont = Cont->getMostDerivedObjectRegion();
|
||||
|
||||
auto State = C.getState();
|
||||
const auto *LCtx = C.getLocationContext();
|
||||
State =
|
||||
createIteratorPosition(State, RetVal, Cont, Elem, LCtx, C.blockCount());
|
||||
const auto *SF = C.getStackFrame();
|
||||
State = createIteratorPosition(State, RetVal, Cont, Elem, SF, C.blockCount());
|
||||
|
||||
C.addTransition(State);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ void IteratorRangeChecker::checkPreStmt(const UnaryOperator *UO,
|
|||
|
||||
ProgramStateRef State = C.getState();
|
||||
UnaryOperatorKind OK = UO->getOpcode();
|
||||
SVal SubVal = State->getSVal(UO->getSubExpr(), C.getLocationContext());
|
||||
SVal SubVal = State->getSVal(UO->getSubExpr(), C.getStackFrame());
|
||||
|
||||
if (isDereferenceOperator(OK)) {
|
||||
verifyDereference(C, SubVal);
|
||||
|
|
@ -162,12 +162,12 @@ void IteratorRangeChecker::checkPreStmt(const BinaryOperator *BO,
|
|||
CheckerContext &C) const {
|
||||
ProgramStateRef State = C.getState();
|
||||
BinaryOperatorKind OK = BO->getOpcode();
|
||||
SVal LVal = State->getSVal(BO->getLHS(), C.getLocationContext());
|
||||
SVal LVal = State->getSVal(BO->getLHS(), C.getStackFrame());
|
||||
|
||||
if (isDereferenceOperator(OK)) {
|
||||
verifyDereference(C, LVal);
|
||||
} else if (isRandomIncrOrDecrOperator(OK)) {
|
||||
SVal RVal = State->getSVal(BO->getRHS(), C.getLocationContext());
|
||||
SVal RVal = State->getSVal(BO->getRHS(), C.getStackFrame());
|
||||
if (!BO->getRHS()->getType()->isIntegralOrEnumerationType())
|
||||
return;
|
||||
verifyRandomIncrOrDecr(C, BinaryOperator::getOverloadedOperator(OK), LVal,
|
||||
|
|
@ -178,7 +178,7 @@ void IteratorRangeChecker::checkPreStmt(const BinaryOperator *BO,
|
|||
void IteratorRangeChecker::checkPreStmt(const ArraySubscriptExpr *ASE,
|
||||
CheckerContext &C) const {
|
||||
ProgramStateRef State = C.getState();
|
||||
SVal LVal = State->getSVal(ASE->getLHS(), C.getLocationContext());
|
||||
SVal LVal = State->getSVal(ASE->getLHS(), C.getStackFrame());
|
||||
verifyDereference(C, LVal);
|
||||
}
|
||||
|
||||
|
|
@ -188,7 +188,7 @@ void IteratorRangeChecker::checkPreStmt(const MemberExpr *ME,
|
|||
return;
|
||||
|
||||
ProgramStateRef State = C.getState();
|
||||
SVal BaseVal = State->getSVal(ME->getBase(), C.getLocationContext());
|
||||
SVal BaseVal = State->getSVal(ME->getBase(), C.getStackFrame());
|
||||
verifyDereference(C, BaseVal);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1031,7 +1031,7 @@ class EmptyLocalizationContextChecker
|
|||
BugReporter &BR;
|
||||
AnalysisManager &Mgr;
|
||||
const CheckerBase *Checker;
|
||||
LocationOrAnalysisDeclContext DCtx;
|
||||
StackFrameOrAnalysisDeclContext DCtx;
|
||||
|
||||
public:
|
||||
MethodCrawler(const ObjCMethodDecl *InMD, BugReporter &InBR,
|
||||
|
|
|
|||
|
|
@ -149,14 +149,12 @@ static const ParmVarDecl *getOriginParam(SVal V, CheckerContext &C,
|
|||
}
|
||||
|
||||
static bool isInMIGCall(CheckerContext &C) {
|
||||
const LocationContext *LC = C.getLocationContext();
|
||||
assert(LC && "Unknown location context");
|
||||
const StackFrame *SF = C.getStackFrame();
|
||||
assert(SF && "Unknown stack frame");
|
||||
|
||||
const StackFrame *SF;
|
||||
// Find the top frame.
|
||||
while (LC) {
|
||||
SF = LC->getStackFrame();
|
||||
LC = SF->getParent();
|
||||
while (SF->getParent()) {
|
||||
SF = SF->getParent();
|
||||
}
|
||||
|
||||
const Decl *D = SF->getDecl();
|
||||
|
|
|
|||
|
|
@ -408,7 +408,7 @@ void MacOSKeychainAPIChecker::checkPostStmt(const CallExpr *CE,
|
|||
// If the argument entered as an enclosing function parameter, skip it to
|
||||
// avoid false positives.
|
||||
if (isEnclosingFunctionParam(ArgExpr) &&
|
||||
C.getLocationContext()->getParent() == nullptr)
|
||||
C.getStackFrame()->getParent() == nullptr)
|
||||
return;
|
||||
|
||||
if (SymbolRef V = getAsPointeeSymbol(ArgExpr, C)) {
|
||||
|
|
@ -440,7 +440,7 @@ const ExplodedNode *
|
|||
MacOSKeychainAPIChecker::getAllocationNode(const ExplodedNode *N,
|
||||
SymbolRef Sym,
|
||||
CheckerContext &C) const {
|
||||
const LocationContext *LeakContext = N->getLocationContext();
|
||||
const StackFrame *LeakStackFrame = N->getStackFrame();
|
||||
// Walk the ExplodedGraph backwards and find the first node that referred to
|
||||
// the tracked symbol.
|
||||
const ExplodedNode *AllocNode = N;
|
||||
|
|
@ -450,9 +450,8 @@ MacOSKeychainAPIChecker::getAllocationNode(const ExplodedNode *N,
|
|||
break;
|
||||
// Allocation node, is the last node in the current or parent context in
|
||||
// which the symbol was tracked.
|
||||
const LocationContext *NContext = N->getLocationContext();
|
||||
if (NContext == LeakContext ||
|
||||
NContext->isParentOf(LeakContext))
|
||||
const StackFrame *NSF = N->getStackFrame();
|
||||
if (NSF == LeakStackFrame || NSF->isParentOf(LeakStackFrame))
|
||||
AllocNode = N;
|
||||
N = N->pred_empty() ? nullptr : *(N->pred_begin());
|
||||
}
|
||||
|
|
@ -477,13 +476,12 @@ MacOSKeychainAPIChecker::generateAllocatedDataNotReleasedReport(
|
|||
const Stmt *AllocStmt = AllocNode->getStmtForDiagnostics();
|
||||
|
||||
if (AllocStmt)
|
||||
LocUsedForUniqueing = PathDiagnosticLocation::createBegin(AllocStmt,
|
||||
C.getSourceManager(),
|
||||
AllocNode->getLocationContext());
|
||||
LocUsedForUniqueing = PathDiagnosticLocation::createBegin(
|
||||
AllocStmt, C.getSourceManager(), AllocNode->getStackFrame());
|
||||
|
||||
auto Report = std::make_unique<PathSensitiveBugReport>(
|
||||
BT, os.str(), N, LocUsedForUniqueing,
|
||||
AllocNode->getLocationContext()->getDecl());
|
||||
AllocNode->getStackFrame()->getDecl());
|
||||
|
||||
Report->addVisitor(std::make_unique<SecKeychainBugVisitor>(AP.first));
|
||||
markInteresting(Report.get(), AP);
|
||||
|
|
@ -631,7 +629,7 @@ MacOSKeychainAPIChecker::SecKeychainBugVisitor::VisitNode(
|
|||
assert(Idx != InvalidIdx && "This should be a call to an allocator.");
|
||||
const Expr *ArgExpr = CE->getArg(FunctionsToTrack[Idx].Param);
|
||||
PathDiagnosticLocation Pos(ArgExpr, BRC.getSourceManager(),
|
||||
N->getLocationContext());
|
||||
N->getStackFrame());
|
||||
return std::make_shared<PathDiagnosticEventPiece>(Pos,
|
||||
"Data is allocated here.");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -985,14 +985,14 @@ protected:
|
|||
|
||||
// A release function stack frame in which memory was released. Used for
|
||||
// miscellaneous false positive suppression.
|
||||
const StackFrame *ReleaseFunctionLC;
|
||||
const StackFrame *ReleaseFunctionSF;
|
||||
|
||||
bool IsLeak;
|
||||
|
||||
public:
|
||||
MallocBugVisitor(SymbolRef S, bool isLeak = false)
|
||||
: Sym(S), Mode(Normal), FailedReallocSymbol(nullptr),
|
||||
ReleaseFunctionLC(nullptr), IsLeak(isLeak) {}
|
||||
ReleaseFunctionSF(nullptr), IsLeak(isLeak) {}
|
||||
|
||||
static void *getTag() {
|
||||
static int Tag = 0;
|
||||
|
|
@ -1491,8 +1491,8 @@ void MallocChecker::checkCXXNewOrCXXDelete(ProgramStateRef State,
|
|||
const FunctionDecl *FD = C.getCalleeDecl(CE);
|
||||
if (const auto *BufArg = getPlacementNewBufferArg(CE, FD)) {
|
||||
// Placement new does not allocate memory
|
||||
auto RetVal = State->getSVal(BufArg, Call.getLocationContext());
|
||||
State = State->BindExpr(CE, C.getLocationContext(), RetVal);
|
||||
auto RetVal = State->getSVal(BufArg, Call.getStackFrame());
|
||||
State = State->BindExpr(CE, C.getStackFrame(), RetVal);
|
||||
C.addTransition(State);
|
||||
return;
|
||||
}
|
||||
|
|
@ -1739,12 +1739,12 @@ ProgramStateRef MallocChecker::ProcessZeroAllocCheck(
|
|||
}
|
||||
|
||||
if (!RetVal)
|
||||
RetVal = State->getSVal(Call.getOriginExpr(), C.getLocationContext());
|
||||
RetVal = State->getSVal(Call.getOriginExpr(), C.getStackFrame());
|
||||
|
||||
assert(Arg);
|
||||
|
||||
auto DefArgVal =
|
||||
State->getSVal(Arg, Call.getLocationContext()).getAs<DefinedSVal>();
|
||||
State->getSVal(Arg, Call.getStackFrame()).getAs<DefinedSVal>();
|
||||
|
||||
if (!DefArgVal)
|
||||
return State;
|
||||
|
|
@ -1828,7 +1828,7 @@ MallocChecker::processNewAllocation(const CXXAllocatorCall &Call,
|
|||
return nullptr;
|
||||
|
||||
const CXXNewExpr *NE = Call.getOriginExpr();
|
||||
const ParentMap &PM = C.getLocationContext()->getParentMap();
|
||||
const ParentMap &PM = C.getStackFrame()->getParentMap();
|
||||
ProgramStateRef State = C.getState();
|
||||
|
||||
// Non-trivial constructors have a chance to escape 'this', but marking all
|
||||
|
|
@ -1942,12 +1942,12 @@ ProgramStateRef MallocChecker::MallocBindRetVal(CheckerContext &C,
|
|||
|
||||
unsigned Count = C.blockCount();
|
||||
SValBuilder &SVB = C.getSValBuilder();
|
||||
const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
|
||||
const StackFrame *SF = C.getPredecessor()->getStackFrame();
|
||||
DefinedSVal RetVal =
|
||||
isAlloca ? SVB.getAllocaRegionVal(CE, LCtx, Count)
|
||||
: SVB.getConjuredHeapSymbolVal(Call.getCFGElementRef(), LCtx,
|
||||
isAlloca ? SVB.getAllocaRegionVal(CE, SF, Count)
|
||||
: SVB.getConjuredHeapSymbolVal(Call.getCFGElementRef(), SF,
|
||||
CE->getType(), Count);
|
||||
return State->BindExpr(CE, C.getLocationContext(), RetVal);
|
||||
return State->BindExpr(CE, C.getStackFrame(), RetVal);
|
||||
}
|
||||
|
||||
ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
|
||||
|
|
@ -2029,11 +2029,11 @@ ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
|
|||
assert(Loc::isLocType(CE->getType()) &&
|
||||
"Allocation functions must return a pointer");
|
||||
|
||||
const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
|
||||
SVal RetVal = State->getSVal(CE, C.getLocationContext());
|
||||
const StackFrame *SF = C.getPredecessor()->getStackFrame();
|
||||
SVal RetVal = State->getSVal(CE, C.getStackFrame());
|
||||
|
||||
// Fill the region with the initialization value.
|
||||
State = State->bindDefaultInitial(RetVal, Init, LCtx);
|
||||
State = State->bindDefaultInitial(RetVal, Init, SF);
|
||||
|
||||
// If Size is somehow undefined at this point, this line prevents a crash.
|
||||
if (Size.isUndef())
|
||||
|
|
@ -2057,7 +2057,7 @@ static ProgramStateRef MallocUpdateRefState(CheckerContext &C, const Expr *E,
|
|||
|
||||
// Get the return value.
|
||||
if (!RetVal)
|
||||
RetVal = State->getSVal(E, C.getLocationContext());
|
||||
RetVal = State->getSVal(E, C.getStackFrame());
|
||||
|
||||
// We expect the malloc functions to return a pointer.
|
||||
if (!RetVal->getAs<Loc>())
|
||||
|
|
@ -2415,7 +2415,7 @@ MallocChecker::FreeMemAux(CheckerContext &C, const Expr *ArgExpr,
|
|||
// conforts languages standards, since reading from freed memory is considered
|
||||
// UB and may result in arbitrary value.
|
||||
State = State->invalidateRegions({location}, Call.getCFGElementRef(),
|
||||
C.blockCount(), C.getLocationContext(),
|
||||
C.blockCount(), C.getStackFrame(),
|
||||
/*CausesPointerEscape=*/false,
|
||||
/*InvalidatedSymbols=*/nullptr);
|
||||
|
||||
|
|
@ -2940,7 +2940,7 @@ MallocChecker::ReallocMemAux(CheckerContext &C, const CallEvent &Call,
|
|||
|
||||
// Get the from and to pointer symbols as in toPtr = realloc(fromPtr, size).
|
||||
SymbolRef FromPtr = arg0Val.getLocSymbolInBase();
|
||||
SVal RetVal = stateRealloc->getSVal(CE, C.getLocationContext());
|
||||
SVal RetVal = stateRealloc->getSVal(CE, C.getStackFrame());
|
||||
SymbolRef ToPtr = RetVal.getAsSymbol();
|
||||
assert(FromPtr && ToPtr &&
|
||||
"By this point, FreeMemAux and MallocMemAux should have checked "
|
||||
|
|
@ -2978,7 +2978,7 @@ ProgramStateRef MallocChecker::CallocMem(CheckerContext &C,
|
|||
MallocChecker::LeakInfo MallocChecker::getAllocationSite(const ExplodedNode *N,
|
||||
SymbolRef Sym,
|
||||
CheckerContext &C) {
|
||||
const LocationContext *LeakContext = N->getLocationContext();
|
||||
const StackFrame *LeakStackFrame = N->getStackFrame();
|
||||
// Walk the ExplodedGraph backwards and find the first node that referred to
|
||||
// the tracked symbol.
|
||||
const ExplodedNode *AllocNode = N;
|
||||
|
|
@ -2998,7 +2998,7 @@ MallocChecker::LeakInfo MallocChecker::getAllocationSite(const ExplodedNode *N,
|
|||
const VarRegion *VR = MR->getBaseRegion()->getAs<VarRegion>();
|
||||
// Do not show local variables belonging to a function other than
|
||||
// where the error is reported.
|
||||
if (!VR || (VR->getStackFrame() == LeakContext->getStackFrame()))
|
||||
if (!VR || (VR->getStackFrame() == LeakStackFrame))
|
||||
ReferenceRegion = MR;
|
||||
}
|
||||
}
|
||||
|
|
@ -3006,9 +3006,8 @@ MallocChecker::LeakInfo MallocChecker::getAllocationSite(const ExplodedNode *N,
|
|||
|
||||
// Allocation node, is the last node in the current or parent context in
|
||||
// which the symbol was tracked.
|
||||
const LocationContext *NContext = N->getLocationContext();
|
||||
if (NContext == LeakContext ||
|
||||
NContext->isParentOf(LeakContext))
|
||||
const StackFrame *NSF = N->getStackFrame();
|
||||
if (NSF == LeakStackFrame || NSF->isParentOf(LeakStackFrame))
|
||||
AllocNode = N;
|
||||
N = N->pred_empty() ? nullptr : *(N->pred_begin());
|
||||
}
|
||||
|
|
@ -3044,9 +3043,8 @@ void MallocChecker::HandleLeak(SymbolRef Sym, ExplodedNode *N,
|
|||
|
||||
const Stmt *AllocationStmt = AllocNode->getStmtForDiagnostics();
|
||||
if (AllocationStmt)
|
||||
LocUsedForUniqueing = PathDiagnosticLocation::createBegin(AllocationStmt,
|
||||
C.getSourceManager(),
|
||||
AllocNode->getLocationContext());
|
||||
LocUsedForUniqueing = PathDiagnosticLocation::createBegin(
|
||||
AllocationStmt, C.getSourceManager(), AllocNode->getStackFrame());
|
||||
|
||||
SmallString<200> buf;
|
||||
llvm::raw_svector_ostream os(buf);
|
||||
|
|
@ -3059,7 +3057,7 @@ void MallocChecker::HandleLeak(SymbolRef Sym, ExplodedNode *N,
|
|||
|
||||
auto R = std::make_unique<PathSensitiveBugReport>(
|
||||
Frontend->LeakBug, os.str(), N, LocUsedForUniqueing,
|
||||
AllocNode->getLocationContext()->getDecl());
|
||||
AllocNode->getStackFrame()->getDecl());
|
||||
R->markInteresting(Sym);
|
||||
R->addVisitor<MallocBugVisitor>(Sym, true);
|
||||
if (ShouldRegisterNoOwnershipChangeVisitor)
|
||||
|
|
@ -3528,14 +3526,13 @@ void MallocChecker::checkPostStmt(const BlockExpr *BE,
|
|||
if (ReferencedVars.empty())
|
||||
return;
|
||||
|
||||
SmallVector<const MemRegion*, 10> Regions;
|
||||
const LocationContext *LC = C.getLocationContext();
|
||||
SmallVector<const MemRegion *, 10> Regions;
|
||||
MemRegionManager &MemMgr = C.getSValBuilder().getRegionManager();
|
||||
|
||||
for (const auto &Var : ReferencedVars) {
|
||||
const VarRegion *VR = Var.getCapturedRegion();
|
||||
if (VR->getSuperRegion() == R) {
|
||||
VR = MemMgr.getVarRegion(VR->getDecl(), LC);
|
||||
VR = MemMgr.getVarRegion(VR->getDecl(), C.getStackFrame());
|
||||
}
|
||||
Regions.push_back(VR);
|
||||
}
|
||||
|
|
@ -3936,7 +3933,7 @@ PathDiagnosticPieceRef MallocBugVisitor::VisitNode(const ExplodedNode *N,
|
|||
if (!S && (!RSCurr || RSCurr->getAllocationFamily().Kind != AF_InnerBuffer))
|
||||
return nullptr;
|
||||
|
||||
const LocationContext *CurrentLC = N->getLocationContext();
|
||||
const StackFrame *CurrentSF = N->getStackFrame();
|
||||
|
||||
// If we find an atomic fetch_add or fetch_sub within the function in which
|
||||
// the pointer was released (before the release), this is likely a release
|
||||
|
|
@ -3946,8 +3943,8 @@ PathDiagnosticPieceRef MallocBugVisitor::VisitNode(const ExplodedNode *N,
|
|||
// original reference count is positive, we should not report use-after-frees
|
||||
// on objects deleted in such functions. This can probably be improved
|
||||
// through better shared pointer modeling.
|
||||
if (ReleaseFunctionLC && (ReleaseFunctionLC == CurrentLC ||
|
||||
ReleaseFunctionLC->isParentOf(CurrentLC))) {
|
||||
if (ReleaseFunctionSF && (ReleaseFunctionSF == CurrentSF ||
|
||||
ReleaseFunctionSF->isParentOf(CurrentSF))) {
|
||||
if (const auto *AE = dyn_cast<AtomicExpr>(S)) {
|
||||
// Check for manual use of atomic builtins.
|
||||
AtomicExpr::AtomicOp Op = AE->getOp();
|
||||
|
|
@ -4024,7 +4021,7 @@ PathDiagnosticPieceRef MallocBugVisitor::VisitNode(const ExplodedNode *N,
|
|||
} else if (const auto *CallE = dyn_cast<CallExpr>(S)) {
|
||||
auto &CEMgr = BRC.getStateManager().getCallEventManager();
|
||||
CallEventRef<> Call =
|
||||
CEMgr.getSimpleCall(CallE, state, CurrentLC, {nullptr, 0});
|
||||
CEMgr.getSimpleCall(CallE, state, CurrentSF, {nullptr, 0});
|
||||
if (const auto *D = dyn_cast_or_null<NamedDecl>(Call->getDecl()))
|
||||
OS << D->getDeclName();
|
||||
else
|
||||
|
|
@ -4048,11 +4045,11 @@ PathDiagnosticPieceRef MallocBugVisitor::VisitNode(const ExplodedNode *N,
|
|||
//
|
||||
// Usually (e.g. in C) we say that the _responsible_ stack frame is the
|
||||
// current innermost stack frame:
|
||||
ReleaseFunctionLC = CurrentLC->getStackFrame();
|
||||
ReleaseFunctionSF = CurrentSF;
|
||||
// ...but if the stack contains a destructor call, then we say that the
|
||||
// outermost destructor stack frame is the _responsible_ one:
|
||||
for (const LocationContext *LC = CurrentLC; LC; LC = LC->getParent()) {
|
||||
if (const auto *DD = dyn_cast<CXXDestructorDecl>(LC->getDecl())) {
|
||||
for (const StackFrame *SF = CurrentSF; SF; SF = SF->getParent()) {
|
||||
if (const auto *DD = dyn_cast<CXXDestructorDecl>(SF->getDecl())) {
|
||||
if (isReferenceCountingPointerDestructor(DD)) {
|
||||
// This immediately looks like a reference-counting destructor.
|
||||
// We're bad at guessing the original reference count of the
|
||||
|
|
@ -4076,7 +4073,7 @@ PathDiagnosticPieceRef MallocBugVisitor::VisitNode(const ExplodedNode *N,
|
|||
// free(buffer);
|
||||
// }
|
||||
//
|
||||
// This way ReleaseFunctionLC will point to outermost destructor and
|
||||
// This way ReleaseFunctionSF will point to outermost destructor and
|
||||
// it would be possible to catch wider range of FP.
|
||||
//
|
||||
// NOTE: it would be great to support smth like that in C, since
|
||||
|
|
@ -4088,7 +4085,7 @@ PathDiagnosticPieceRef MallocBugVisitor::VisitNode(const ExplodedNode *N,
|
|||
// if (refPut(data))
|
||||
// doFree(data);
|
||||
// }
|
||||
ReleaseFunctionLC = LC->getStackFrame();
|
||||
ReleaseFunctionSF = SF;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4142,8 +4139,7 @@ PathDiagnosticPieceRef MallocBugVisitor::VisitNode(const ExplodedNode *N,
|
|||
Pos = PathDiagnosticLocation(PostImplCall->getLocation(),
|
||||
BRC.getSourceManager());
|
||||
} else {
|
||||
Pos = PathDiagnosticLocation(S, BRC.getSourceManager(),
|
||||
N->getLocationContext());
|
||||
Pos = PathDiagnosticLocation(S, BRC.getSourceManager(), N->getStackFrame());
|
||||
}
|
||||
|
||||
auto P = std::make_shared<PathDiagnosticEventPiece>(Pos, Msg, true);
|
||||
|
|
|
|||
|
|
@ -193,8 +193,8 @@ void MismatchedIteratorChecker::checkPreStmt(const BinaryOperator *BO,
|
|||
return;
|
||||
|
||||
ProgramStateRef State = C.getState();
|
||||
SVal LVal = State->getSVal(BO->getLHS(), C.getLocationContext());
|
||||
SVal RVal = State->getSVal(BO->getRHS(), C.getLocationContext());
|
||||
SVal LVal = State->getSVal(BO->getLHS(), C.getStackFrame());
|
||||
SVal RVal = State->getSVal(BO->getRHS(), C.getStackFrame());
|
||||
verifyMatch(C, LVal, RVal);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ public:
|
|||
const InvalidatedSymbols *Invalidated,
|
||||
ArrayRef<const MemRegion *> RequestedRegions,
|
||||
ArrayRef<const MemRegion *> InvalidatedRegions,
|
||||
const LocationContext *LCtx, const CallEvent *Call) const;
|
||||
const StackFrame *SF, const CallEvent *Call) const;
|
||||
void printState(raw_ostream &Out, ProgramStateRef State,
|
||||
const char *NL, const char *Sep) const override;
|
||||
|
||||
|
|
@ -219,7 +219,7 @@ private:
|
|||
ExplodedNode *tryToReportBug(const MemRegion *Region, const CXXRecordDecl *RD,
|
||||
CheckerContext &C, MisuseKind MK) const;
|
||||
|
||||
bool isInMoveSafeContext(const LocationContext *LC) const;
|
||||
bool isInMoveSafeStackFrame(const StackFrame *SF) const;
|
||||
bool isStateResetMethod(const CXXMethodDecl *MethodDec) const;
|
||||
bool isMoveSafeMethod(const CXXMethodDecl *MethodDec) const;
|
||||
const ExplodedNode *getMoveLocation(const ExplodedNode *N,
|
||||
|
|
@ -328,8 +328,7 @@ MoveChecker::MovedBugVisitor::VisitNode(const ExplodedNode *N,
|
|||
}
|
||||
|
||||
// Generate the extra diagnostic.
|
||||
PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
|
||||
N->getLocationContext());
|
||||
PathDiagnosticLocation Pos(S, BRC.getSourceManager(), N->getStackFrame());
|
||||
return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(), true);
|
||||
}
|
||||
|
||||
|
|
@ -362,8 +361,8 @@ void MoveChecker::modelUse(ProgramStateRef State, const MemRegion *Region,
|
|||
if (MK == MK_Dereference && OK.StdKind != SK_SmartPtr)
|
||||
MK = MK_FunCall;
|
||||
|
||||
if (!RS || !shouldWarnAbout(OK, MK)
|
||||
|| isInMoveSafeContext(C.getLocationContext())) {
|
||||
if (!RS || !shouldWarnAbout(OK, MK) ||
|
||||
isInMoveSafeStackFrame(C.getStackFrame())) {
|
||||
// Finalize changes made by the caller.
|
||||
C.addTransition(State);
|
||||
return;
|
||||
|
|
@ -403,7 +402,7 @@ ExplodedNode *MoveChecker::tryToReportBug(const MemRegion *Region,
|
|||
|
||||
if (const Stmt *MoveStmt = MoveNode->getStmtForDiagnostics())
|
||||
LocUsedForUniqueing = PathDiagnosticLocation::createBegin(
|
||||
MoveStmt, C.getSourceManager(), MoveNode->getLocationContext());
|
||||
MoveStmt, C.getSourceManager(), MoveNode->getStackFrame());
|
||||
|
||||
// Creating the error message.
|
||||
llvm::SmallString<128> Str;
|
||||
|
|
@ -432,7 +431,7 @@ ExplodedNode *MoveChecker::tryToReportBug(const MemRegion *Region,
|
|||
|
||||
auto R = std::make_unique<PathSensitiveBugReport>(
|
||||
BT, OS.str(), N, LocUsedForUniqueing,
|
||||
MoveNode->getLocationContext()->getDecl());
|
||||
MoveNode->getStackFrame()->getDecl());
|
||||
R->addVisitor(std::make_unique<MovedBugVisitor>(*this, Region, RD, MK));
|
||||
C.emitReport(std::move(R));
|
||||
return N;
|
||||
|
|
@ -530,18 +529,18 @@ bool MoveChecker::isStateResetMethod(const CXXMethodDecl *MethodDec) const {
|
|||
|
||||
// Don't report an error inside a move related operation.
|
||||
// We assume that the programmer knows what she does.
|
||||
bool MoveChecker::isInMoveSafeContext(const LocationContext *LC) const {
|
||||
bool MoveChecker::isInMoveSafeStackFrame(const StackFrame *SF) const {
|
||||
do {
|
||||
const auto *CtxDec = LC->getDecl();
|
||||
auto *CtorDec = dyn_cast_or_null<CXXConstructorDecl>(CtxDec);
|
||||
auto *DtorDec = dyn_cast_or_null<CXXDestructorDecl>(CtxDec);
|
||||
auto *MethodDec = dyn_cast_or_null<CXXMethodDecl>(CtxDec);
|
||||
const auto *SFDec = SF->getDecl();
|
||||
auto *CtorDec = dyn_cast_or_null<CXXConstructorDecl>(SFDec);
|
||||
auto *DtorDec = dyn_cast_or_null<CXXDestructorDecl>(SFDec);
|
||||
auto *MethodDec = dyn_cast_or_null<CXXMethodDecl>(SFDec);
|
||||
if (DtorDec || (CtorDec && CtorDec->isCopyOrMoveConstructor()) ||
|
||||
(MethodDec && MethodDec->isOverloadedOperator() &&
|
||||
MethodDec->getOverloadedOperator() == OO_Equal) ||
|
||||
isStateResetMethod(MethodDec) || isMoveSafeMethod(MethodDec))
|
||||
return true;
|
||||
} while ((LC = LC->getParent()));
|
||||
} while ((SF = SF->getParent()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -703,8 +702,8 @@ void MoveChecker::checkDeadSymbols(SymbolReaper &SymReaper,
|
|||
ProgramStateRef MoveChecker::checkRegionChanges(
|
||||
ProgramStateRef State, const InvalidatedSymbols *Invalidated,
|
||||
ArrayRef<const MemRegion *> RequestedRegions,
|
||||
ArrayRef<const MemRegion *> InvalidatedRegions,
|
||||
const LocationContext *LCtx, const CallEvent *Call) const {
|
||||
ArrayRef<const MemRegion *> InvalidatedRegions, const StackFrame *SF,
|
||||
const CallEvent *Call) const {
|
||||
if (Call) {
|
||||
// Relax invalidation upon function calls: only invalidate parameters
|
||||
// that are passed directly via non-const pointers or non-const references
|
||||
|
|
|
|||
|
|
@ -70,8 +70,7 @@ NoOwnershipChangeVisitor::getFunctionName(const ExplodedNode *CallEnterN) {
|
|||
|
||||
bool NoOwnershipChangeVisitor::wasModifiedInFunction(
|
||||
const ExplodedNode *CallEnterN, const ExplodedNode *CallExitEndN) {
|
||||
const Decl *Callee =
|
||||
CallExitEndN->getFirstPred()->getLocationContext()->getDecl();
|
||||
const Decl *Callee = CallExitEndN->getFirstPred()->getStackFrame()->getDecl();
|
||||
if (!doesFnIntendToHandleOwnership(
|
||||
Callee,
|
||||
CallExitEndN->getState()->getAnalysisManager().getASTContext()))
|
||||
|
|
|
|||
|
|
@ -239,9 +239,9 @@ void NonNullParamChecker::checkBeginFunction(CheckerContext &Context) const {
|
|||
if (!Context.inTopFrame())
|
||||
return;
|
||||
|
||||
const LocationContext *LocContext = Context.getLocationContext();
|
||||
const StackFrame *SF = Context.getStackFrame();
|
||||
|
||||
const Decl *FD = LocContext->getDecl();
|
||||
const Decl *FD = SF->getDecl();
|
||||
// AnyCall helps us here to avoid checking for FunctionDecl and ObjCMethodDecl
|
||||
// separately and aggregates interfaces of these classes.
|
||||
auto AbstractCall = AnyCall::forDecl(FD);
|
||||
|
|
@ -262,7 +262,7 @@ void NonNullParamChecker::checkBeginFunction(CheckerContext &Context) const {
|
|||
if (!Parameter->getType()->isPointerType())
|
||||
continue;
|
||||
|
||||
Loc ParameterLoc = State->getLValue(Parameter, LocContext);
|
||||
Loc ParameterLoc = State->getLValue(Parameter, SF);
|
||||
// We never consider top-level function parameters undefined.
|
||||
auto StoredVal =
|
||||
State->getSVal(ParameterLoc).castAs<DefinedOrUnknownSVal>();
|
||||
|
|
|
|||
|
|
@ -367,8 +367,7 @@ PathDiagnosticPieceRef NullabilityChecker::NullabilityBugVisitor::VisitNode(
|
|||
.str();
|
||||
|
||||
// Generate the extra diagnostic.
|
||||
PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
|
||||
N->getLocationContext());
|
||||
PathDiagnosticLocation Pos(S, BRC.getSourceManager(), N->getStackFrame());
|
||||
return std::make_shared<PathDiagnosticEventPiece>(Pos, InfoText, true);
|
||||
}
|
||||
|
||||
|
|
@ -399,15 +398,14 @@ static bool checkValueAtLValForInvariantViolation(ProgramStateRef State,
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
checkParamsForPreconditionViolation(ArrayRef<ParmVarDecl *> Params,
|
||||
ProgramStateRef State,
|
||||
const LocationContext *LocCtxt) {
|
||||
static bool checkParamsForPreconditionViolation(ArrayRef<ParmVarDecl *> Params,
|
||||
ProgramStateRef State,
|
||||
const StackFrame *SF) {
|
||||
for (const auto *ParamDecl : Params) {
|
||||
if (ParamDecl->isParameterPack())
|
||||
break;
|
||||
|
||||
SVal LV = State->getLValue(ParamDecl, LocCtxt);
|
||||
SVal LV = State->getLValue(ParamDecl, SF);
|
||||
if (checkValueAtLValForInvariantViolation(State, LV,
|
||||
ParamDecl->getType())) {
|
||||
return true;
|
||||
|
|
@ -416,18 +414,17 @@ checkParamsForPreconditionViolation(ArrayRef<ParmVarDecl *> Params,
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
checkSelfIvarsForInvariantViolation(ProgramStateRef State,
|
||||
const LocationContext *LocCtxt) {
|
||||
auto *MD = dyn_cast<ObjCMethodDecl>(LocCtxt->getDecl());
|
||||
static bool checkSelfIvarsForInvariantViolation(ProgramStateRef State,
|
||||
const StackFrame *SF) {
|
||||
auto *MD = dyn_cast<ObjCMethodDecl>(SF->getDecl());
|
||||
if (!MD || !MD->isInstanceMethod())
|
||||
return false;
|
||||
|
||||
const ImplicitParamDecl *SelfDecl = LocCtxt->getSelfDecl();
|
||||
const ImplicitParamDecl *SelfDecl = SF->getSelfDecl();
|
||||
if (!SelfDecl)
|
||||
return false;
|
||||
|
||||
SVal SelfVal = State->getSVal(State->getRegion(SelfDecl, LocCtxt));
|
||||
SVal SelfVal = State->getSVal(State->getRegion(SelfDecl, SF));
|
||||
|
||||
const ObjCObjectPointerType *SelfType =
|
||||
dyn_cast<ObjCObjectPointerType>(SelfDecl->getType());
|
||||
|
|
@ -452,8 +449,8 @@ static bool checkInvariantViolation(ProgramStateRef State, ExplodedNode *N,
|
|||
if (State->get<InvariantViolated>())
|
||||
return true;
|
||||
|
||||
const LocationContext *LocCtxt = C.getLocationContext();
|
||||
const Decl *D = LocCtxt->getDecl();
|
||||
const StackFrame *SF = C.getStackFrame();
|
||||
const Decl *D = SF->getDecl();
|
||||
if (!D)
|
||||
return false;
|
||||
|
||||
|
|
@ -467,8 +464,8 @@ static bool checkInvariantViolation(ProgramStateRef State, ExplodedNode *N,
|
|||
else
|
||||
return false;
|
||||
|
||||
if (checkParamsForPreconditionViolation(Params, State, LocCtxt) ||
|
||||
checkSelfIvarsForInvariantViolation(State, LocCtxt)) {
|
||||
if (checkParamsForPreconditionViolation(Params, State, SF) ||
|
||||
checkSelfIvarsForInvariantViolation(State, SF)) {
|
||||
if (!N->isSink())
|
||||
C.addTransition(State->set<InvariantViolated>(true), N);
|
||||
return true;
|
||||
|
|
@ -565,8 +562,8 @@ void NullabilityChecker::checkBeginFunction(CheckerContext &C) const {
|
|||
if (!C.inTopFrame())
|
||||
return;
|
||||
|
||||
const LocationContext *LCtx = C.getLocationContext();
|
||||
auto AbstractCall = AnyCall::forDecl(LCtx->getDecl());
|
||||
const StackFrame *SF = C.getStackFrame();
|
||||
auto AbstractCall = AnyCall::forDecl(SF->getDecl());
|
||||
if (!AbstractCall || AbstractCall->parameters().empty())
|
||||
return;
|
||||
|
||||
|
|
@ -580,7 +577,7 @@ void NullabilityChecker::checkBeginFunction(CheckerContext &C) const {
|
|||
if (RequiredNullability != Nullability::Nullable)
|
||||
continue;
|
||||
|
||||
const VarRegion *ParamRegion = State->getRegion(Param, LCtx);
|
||||
const VarRegion *ParamRegion = State->getRegion(Param, SF);
|
||||
const MemRegion *ParamPointeeRegion =
|
||||
State->getSVal(ParamRegion).getAsRegion();
|
||||
if (!ParamPointeeRegion)
|
||||
|
|
@ -668,8 +665,7 @@ void NullabilityChecker::checkPreStmt(const ReturnStmt *S,
|
|||
bool InSuppressedMethodFamily = false;
|
||||
|
||||
QualType RequiredRetType;
|
||||
AnalysisDeclContext *DeclCtxt =
|
||||
C.getLocationContext()->getAnalysisDeclContext();
|
||||
AnalysisDeclContext *DeclCtxt = C.getStackFrame()->getAnalysisDeclContext();
|
||||
const Decl *D = DeclCtxt->getDecl();
|
||||
if (auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
|
||||
// HACK: This is a big hammer to avoid warning when there are defensive
|
||||
|
|
@ -690,7 +686,7 @@ void NullabilityChecker::checkPreStmt(const ReturnStmt *S,
|
|||
NullConstraint Nullness = getNullConstraint(*RetSVal, State);
|
||||
|
||||
Nullability RequiredNullability = getNullabilityAnnotation(RequiredRetType);
|
||||
if (const auto *FunDecl = C.getLocationContext()->getDecl();
|
||||
if (const auto *FunDecl = C.getStackFrame()->getDecl();
|
||||
FunDecl && FunDecl->getAttr<ReturnsNonNullAttr>() &&
|
||||
(RequiredNullability == Nullability::Unspecified ||
|
||||
RequiredNullability == Nullability::Nullable)) {
|
||||
|
|
|
|||
|
|
@ -117,8 +117,7 @@ void ObjCSuperDeallocChecker::checkPostObjCMessage(const ObjCMethodCall &M,
|
|||
return;
|
||||
|
||||
ProgramStateRef State = C.getState();
|
||||
const LocationContext *LC = C.getLocationContext();
|
||||
SymbolRef SelfSymbol = State->getSelfSVal(LC).getAsSymbol();
|
||||
SymbolRef SelfSymbol = State->getSelfSVal(C.getStackFrame()).getAsSymbol();
|
||||
assert(SelfSymbol && "No receiver symbol at call to [super dealloc]?");
|
||||
|
||||
// We add this transition in checkPostObjCMessage to avoid warning when
|
||||
|
|
|
|||
|
|
@ -251,8 +251,8 @@ public:
|
|||
ProgramStateRef
|
||||
checkRegionChanges(ProgramStateRef State, const InvalidatedSymbols *Symbols,
|
||||
ArrayRef<const MemRegion *> ExplicitRegions,
|
||||
ArrayRef<const MemRegion *> Regions,
|
||||
const LocationContext *LCtx, const CallEvent *Call) const;
|
||||
ArrayRef<const MemRegion *> Regions, const StackFrame *SF,
|
||||
const CallEvent *Call) const;
|
||||
void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
|
||||
const char *Sep) const override;
|
||||
|
||||
|
|
@ -694,7 +694,7 @@ void PthreadLockChecker::checkDeadSymbols(SymbolReaper &SymReaper,
|
|||
ProgramStateRef PthreadLockChecker::checkRegionChanges(
|
||||
ProgramStateRef State, const InvalidatedSymbols *Symbols,
|
||||
ArrayRef<const MemRegion *> ExplicitRegions,
|
||||
ArrayRef<const MemRegion *> Regions, const LocationContext *LCtx,
|
||||
ArrayRef<const MemRegion *> Regions, const StackFrame *SF,
|
||||
const CallEvent *Call) const {
|
||||
|
||||
bool IsLibraryFunction = false;
|
||||
|
|
|
|||
|
|
@ -162,13 +162,13 @@ void RetainCountChecker::checkPostStmt(const BlockExpr *BE,
|
|||
// via captured variables, even though captured variables result in a copy
|
||||
// and in implicit increment/decrement of a retain count.
|
||||
SmallVector<const MemRegion*, 10> Regions;
|
||||
const LocationContext *LC = C.getLocationContext();
|
||||
const StackFrame *SF = C.getStackFrame();
|
||||
MemRegionManager &MemMgr = C.getSValBuilder().getRegionManager();
|
||||
|
||||
for (auto Var : ReferencedVars) {
|
||||
const VarRegion *VR = Var.getCapturedRegion();
|
||||
if (VR->getSuperRegion() == R) {
|
||||
VR = MemMgr.getVarRegion(VR->getDecl(), LC);
|
||||
VR = MemMgr.getVarRegion(VR->getDecl(), SF);
|
||||
}
|
||||
Regions.push_back(VR);
|
||||
}
|
||||
|
|
@ -245,8 +245,7 @@ void RetainCountChecker::processObjCLiterals(CheckerContext &C,
|
|||
|
||||
// Return the object as autoreleased.
|
||||
// RetEffect RE = RetEffect::MakeNotOwned(ObjKind::ObjC);
|
||||
if (SymbolRef sym =
|
||||
state->getSVal(Ex, pred->getLocationContext()).getAsSymbol()) {
|
||||
if (SymbolRef sym = state->getSVal(Ex, pred->getStackFrame()).getAsSymbol()) {
|
||||
QualType ResultTy = Ex->getType();
|
||||
state = setRefBinding(state, sym,
|
||||
RefVal::makeNotOwned(ObjKind::ObjC, ResultTy));
|
||||
|
|
@ -340,7 +339,7 @@ static bool isReceiverUnconsumedSelf(const CallEvent &Call) {
|
|||
// Check if the message is not consumed, we know it will not be used in
|
||||
// an assignment, ex: "self = [super init]".
|
||||
return MC->getMethodFamily() == OMF_init && MC->isReceiverSelfOrSuper() &&
|
||||
!Call.getLocationContext()
|
||||
!Call.getStackFrame()
|
||||
->getAnalysisDeclContext()
|
||||
->getParentMap()
|
||||
.isConsumedExpr(Call.getOriginExpr());
|
||||
|
|
@ -910,7 +909,7 @@ bool RetainCountChecker::evalCall(const CallEvent &Call,
|
|||
// annotate attribute. If it does, we will not inline it.
|
||||
bool hasTrustedImplementationAnnotation = false;
|
||||
|
||||
const LocationContext *LCtx = C.getLocationContext();
|
||||
const StackFrame *SF = C.getStackFrame();
|
||||
|
||||
using BehaviorSummary = RetainSummaryManager::BehaviorSummary;
|
||||
std::optional<BehaviorSummary> BSmr =
|
||||
|
|
@ -929,7 +928,7 @@ bool RetainCountChecker::evalCall(const CallEvent &Call,
|
|||
(BSmr == BehaviorSummary::IdentityThis)
|
||||
? cast<CXXMemberCallExpr>(CE)->getImplicitObjectArgument()
|
||||
: CE->getArg(0);
|
||||
SVal RetVal = state->getSVal(BindReturnTo, LCtx);
|
||||
SVal RetVal = state->getSVal(BindReturnTo, SF);
|
||||
|
||||
// If the receiver is unknown or the function has
|
||||
// 'rc_ownership_trusted_implementation' annotate attribute, conjure a
|
||||
|
|
@ -942,7 +941,7 @@ bool RetainCountChecker::evalCall(const CallEvent &Call,
|
|||
}
|
||||
|
||||
// Bind the value.
|
||||
state = state->BindExpr(CE, LCtx, RetVal, /*Invalidate=*/false);
|
||||
state = state->BindExpr(CE, SF, RetVal, /*Invalidate=*/false);
|
||||
|
||||
if (BSmr == BehaviorSummary::IdentityOrZero) {
|
||||
// Add a branch where the output is zero.
|
||||
|
|
@ -950,7 +949,7 @@ bool RetainCountChecker::evalCall(const CallEvent &Call,
|
|||
|
||||
// Assume that output is zero on the other branch.
|
||||
NullOutputState = NullOutputState->BindExpr(
|
||||
CE, LCtx, C.getSValBuilder().makeNullWithType(ResultTy),
|
||||
CE, SF, C.getSValBuilder().makeNullWithType(ResultTy),
|
||||
/*Invalidate=*/false);
|
||||
C.addTransition(NullOutputState, &getCastFailTag());
|
||||
|
||||
|
|
@ -988,7 +987,7 @@ ExplodedNode * RetainCountChecker::processReturn(const ReturnStmt *S,
|
|||
ProgramStateRef state = C.getState();
|
||||
// We need to dig down to the symbolic base here because various
|
||||
// custom allocators do sometimes return the symbol with an offset.
|
||||
SymbolRef Sym = state->getSValAsScalarOrLoc(RetE, C.getLocationContext())
|
||||
SymbolRef Sym = state->getSValAsScalarOrLoc(RetE, C.getStackFrame())
|
||||
.getAsLocSymbol(/*IncludeBaseRegions=*/true);
|
||||
if (!Sym)
|
||||
return Pred;
|
||||
|
|
@ -1185,7 +1184,7 @@ ProgramStateRef RetainCountChecker::evalAssume(ProgramStateRef state,
|
|||
ProgramStateRef RetainCountChecker::checkRegionChanges(
|
||||
ProgramStateRef state, const InvalidatedSymbols *invalidated,
|
||||
ArrayRef<const MemRegion *> ExplicitRegions,
|
||||
ArrayRef<const MemRegion *> Regions, const LocationContext *LCtx,
|
||||
ArrayRef<const MemRegion *> Regions, const StackFrame *SF,
|
||||
const CallEvent *Call) const {
|
||||
if (!invalidated)
|
||||
return state;
|
||||
|
|
@ -1332,8 +1331,8 @@ void RetainCountChecker::checkBeginFunction(CheckerContext &Ctx) const {
|
|||
return;
|
||||
|
||||
RetainSummaryManager &SmrMgr = getSummaryManager(Ctx);
|
||||
const LocationContext *LCtx = Ctx.getLocationContext();
|
||||
const Decl *D = LCtx->getDecl();
|
||||
const StackFrame *SF = Ctx.getStackFrame();
|
||||
const Decl *D = SF->getDecl();
|
||||
std::optional<AnyCall> C = AnyCall::forDecl(D);
|
||||
|
||||
if (!C || SmrMgr.isTrustedReferenceCountImplementation(D))
|
||||
|
|
@ -1345,7 +1344,7 @@ void RetainCountChecker::checkBeginFunction(CheckerContext &Ctx) const {
|
|||
|
||||
for (unsigned idx = 0, e = C->param_size(); idx != e; ++idx) {
|
||||
const ParmVarDecl *Param = C->parameters()[idx];
|
||||
SymbolRef Sym = state->getSVal(state->getRegion(Param, LCtx)).getAsSymbol();
|
||||
SymbolRef Sym = state->getSVal(state->getRegion(Param, SF)).getAsSymbol();
|
||||
|
||||
QualType Ty = Param->getType();
|
||||
const ArgEffect *AE = CalleeSideArgEffects.lookup(idx);
|
||||
|
|
@ -1376,9 +1375,9 @@ void RetainCountChecker::checkEndFunction(const ReturnStmt *RS,
|
|||
RefBindingsTy B = state->get<RefBindings>();
|
||||
|
||||
// Don't process anything within synthesized bodies.
|
||||
const LocationContext *LCtx = Pred->getLocationContext();
|
||||
if (LCtx->getAnalysisDeclContext()->isBodyAutosynthesized()) {
|
||||
assert(!LCtx->inTopFrame());
|
||||
const StackFrame *SF = Pred->getStackFrame();
|
||||
if (SF->getAnalysisDeclContext()->isBodyAutosynthesized()) {
|
||||
assert(!SF->inTopFrame());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1388,11 +1387,11 @@ void RetainCountChecker::checkEndFunction(const ReturnStmt *RS,
|
|||
return;
|
||||
}
|
||||
|
||||
// If the current LocationContext has a parent, don't check for leaks.
|
||||
// If the current StackFrame has a parent, don't check for leaks.
|
||||
// We will do that later.
|
||||
// FIXME: we should instead check for imbalances of the retain/releases,
|
||||
// and suggest annotations.
|
||||
if (LCtx->getParent())
|
||||
if (SF->getParent())
|
||||
return;
|
||||
|
||||
B = state->get<RefBindings>();
|
||||
|
|
|
|||
|
|
@ -309,8 +309,7 @@ public:
|
|||
checkRegionChanges(ProgramStateRef state,
|
||||
const InvalidatedSymbols *invalidated,
|
||||
ArrayRef<const MemRegion *> ExplicitRegions,
|
||||
ArrayRef<const MemRegion *> Regions,
|
||||
const LocationContext* LCtx,
|
||||
ArrayRef<const MemRegion *> Regions, const StackFrame *SF,
|
||||
const CallEvent *Call) const;
|
||||
|
||||
ExplodedNode* checkReturnWithRetEffect(const ReturnStmt *S, CheckerContext &C,
|
||||
|
|
|
|||
|
|
@ -117,8 +117,8 @@ static bool shouldGenerateNote(llvm::raw_string_ostream &os,
|
|||
/// corresponding to the symbol @c Sym.
|
||||
/// If none found, returns std::nullopt.
|
||||
static std::optional<unsigned>
|
||||
findArgIdxOfSymbol(ProgramStateRef CurrSt, const LocationContext *LCtx,
|
||||
SymbolRef &Sym, std::optional<CallEventRef<>> CE) {
|
||||
findArgIdxOfSymbol(ProgramStateRef CurrSt, const StackFrame *SF, SymbolRef &Sym,
|
||||
std::optional<CallEventRef<>> CE) {
|
||||
if (!CE)
|
||||
return std::nullopt;
|
||||
|
||||
|
|
@ -157,7 +157,7 @@ static std::string findAllocatedObjectName(const Stmt *S, QualType QT) {
|
|||
}
|
||||
|
||||
static void generateDiagnosticsForCallLike(ProgramStateRef CurrSt,
|
||||
const LocationContext *LCtx,
|
||||
const StackFrame *SF,
|
||||
const RefVal &CurrV, SymbolRef &Sym,
|
||||
const Stmt *S,
|
||||
llvm::raw_string_ostream &os) {
|
||||
|
|
@ -165,7 +165,7 @@ static void generateDiagnosticsForCallLike(ProgramStateRef CurrSt,
|
|||
if (const CallExpr *CE = dyn_cast<CallExpr>(S)) {
|
||||
// Get the name of the callee (if it is available)
|
||||
// from the tracked SVal.
|
||||
SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee(), LCtx);
|
||||
SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee(), SF);
|
||||
const FunctionDecl *FD = X.getAsFunctionDecl();
|
||||
|
||||
// If failed, try to get it from AST.
|
||||
|
|
@ -184,7 +184,7 @@ static void generateDiagnosticsForCallLike(ProgramStateRef CurrSt,
|
|||
} else {
|
||||
assert(isa<ObjCMessageExpr>(S));
|
||||
CallEventRef<ObjCMethodCall> Call = Mgr.getObjCMethodCall(
|
||||
cast<ObjCMessageExpr>(S), CurrSt, LCtx, {nullptr, 0});
|
||||
cast<ObjCMessageExpr>(S), CurrSt, SF, {nullptr, 0});
|
||||
|
||||
switch (Call->getMessageKind()) {
|
||||
case OCM_Message:
|
||||
|
|
@ -199,8 +199,8 @@ static void generateDiagnosticsForCallLike(ProgramStateRef CurrSt,
|
|||
}
|
||||
}
|
||||
|
||||
std::optional<CallEventRef<>> CE = Mgr.getCall(S, CurrSt, LCtx, {nullptr, 0});
|
||||
auto Idx = findArgIdxOfSymbol(CurrSt, LCtx, Sym, CE);
|
||||
std::optional<CallEventRef<>> CE = Mgr.getCall(S, CurrSt, SF, {nullptr, 0});
|
||||
auto Idx = findArgIdxOfSymbol(CurrSt, SF, Sym, CE);
|
||||
|
||||
// If index is not found, we assume that the symbol was returned.
|
||||
if (!Idx) {
|
||||
|
|
@ -303,15 +303,15 @@ private:
|
|||
|
||||
/// Find the first node with the parent stack frame.
|
||||
static const ExplodedNode *getCalleeNode(const ExplodedNode *Pred) {
|
||||
const StackFrame *SC = Pred->getStackFrame();
|
||||
if (SC->inTopFrame())
|
||||
const StackFrame *SF = Pred->getStackFrame();
|
||||
if (SF->inTopFrame())
|
||||
return nullptr;
|
||||
const StackFrame *PC = SC->getParent()->getStackFrame();
|
||||
if (!PC)
|
||||
const StackFrame *PSF = SF->getParent();
|
||||
if (!PSF)
|
||||
return nullptr;
|
||||
|
||||
const ExplodedNode *N = Pred;
|
||||
while (N && N->getStackFrame() != PC) {
|
||||
while (N && N->getStackFrame() != PSF) {
|
||||
N = N->getFirstPred();
|
||||
}
|
||||
return N;
|
||||
|
|
@ -422,7 +422,7 @@ RefCountReportVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
|
|||
const ExplodedNode *PrevNode = N->getFirstPred();
|
||||
ProgramStateRef PrevSt = PrevNode->getState();
|
||||
ProgramStateRef CurrSt = N->getState();
|
||||
const LocationContext *LCtx = N->getLocationContext();
|
||||
const StackFrame *SF = N->getStackFrame();
|
||||
|
||||
const RefVal* CurrT = getRefBinding(CurrSt, Sym);
|
||||
if (!CurrT)
|
||||
|
|
@ -447,9 +447,8 @@ RefCountReportVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
|
|||
if (!PrevT) {
|
||||
const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt();
|
||||
|
||||
if (isa<ObjCIvarRefExpr>(S) &&
|
||||
isSynthesizedAccessor(LCtx->getStackFrame())) {
|
||||
S = LCtx->getStackFrame()->getCallSite();
|
||||
if (isa<ObjCIvarRefExpr>(S) && isSynthesizedAccessor(SF)) {
|
||||
S = SF->getCallSite();
|
||||
}
|
||||
|
||||
if (isa<ObjCArrayLiteral>(S)) {
|
||||
|
|
@ -477,10 +476,10 @@ RefCountReportVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
|
|||
} else if (isa<ObjCIvarRefExpr>(S)) {
|
||||
os << "Object loaded from instance variable";
|
||||
} else {
|
||||
generateDiagnosticsForCallLike(CurrSt, LCtx, CurrV, Sym, S, os);
|
||||
generateDiagnosticsForCallLike(CurrSt, SF, CurrV, Sym, S, os);
|
||||
}
|
||||
|
||||
PathDiagnosticLocation Pos(S, SM, N->getLocationContext());
|
||||
PathDiagnosticLocation Pos(S, SM, N->getStackFrame());
|
||||
return std::make_shared<PathDiagnosticEventPiece>(Pos, sbuf);
|
||||
}
|
||||
|
||||
|
|
@ -508,16 +507,15 @@ RefCountReportVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
|
|||
|
||||
// Retrieve the value of the argument. Is it the symbol
|
||||
// we are interested in?
|
||||
if (CurrSt->getSValAsScalarOrLoc(*AI, LCtx).getAsLocSymbol() != Sym)
|
||||
if (CurrSt->getSValAsScalarOrLoc(*AI, SF).getAsLocSymbol() != Sym)
|
||||
continue;
|
||||
|
||||
// We have an argument. Get the effect!
|
||||
DeallocSent = true;
|
||||
}
|
||||
} else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) {
|
||||
if (const Expr *receiver = ME->getInstanceReceiver()) {
|
||||
if (CurrSt->getSValAsScalarOrLoc(receiver, LCtx)
|
||||
.getAsLocSymbol() == Sym) {
|
||||
if (const Expr *R = ME->getInstanceReceiver()) {
|
||||
if (CurrSt->getSValAsScalarOrLoc(R, SF).getAsLocSymbol() == Sym) {
|
||||
// The symbol we are tracking is the receiver.
|
||||
DeallocSent = true;
|
||||
}
|
||||
|
|
@ -532,15 +530,14 @@ RefCountReportVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
|
|||
return nullptr; // We have nothing to say!
|
||||
|
||||
const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt();
|
||||
PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
|
||||
N->getLocationContext());
|
||||
PathDiagnosticLocation Pos(S, BRC.getSourceManager(), N->getStackFrame());
|
||||
auto P = std::make_shared<PathDiagnosticEventPiece>(Pos, sbuf);
|
||||
|
||||
// Add the range by scanning the children of the statement for any bindings
|
||||
// to Sym.
|
||||
for (const Stmt *Child : S->children())
|
||||
if (const Expr *Exp = dyn_cast_or_null<Expr>(Child))
|
||||
if (CurrSt->getSValAsScalarOrLoc(Exp, LCtx).getAsLocSymbol() == Sym) {
|
||||
if (CurrSt->getSValAsScalarOrLoc(Exp, SF).getAsLocSymbol() == Sym) {
|
||||
P->addRange(Exp->getSourceRange());
|
||||
break;
|
||||
}
|
||||
|
|
@ -598,16 +595,16 @@ namespace {
|
|||
// Find the first node in the current function context that referred to the
|
||||
// tracked symbol and the memory location that value was stored to. Note, the
|
||||
// value is only reported if the allocation occurred in the same function as
|
||||
// the leak. The function can also return a location context, which should be
|
||||
// the leak. The function can also return a stack frame, which should be
|
||||
// treated as interesting.
|
||||
struct AllocationInfo {
|
||||
const ExplodedNode* N;
|
||||
const MemRegion *R;
|
||||
const LocationContext *InterestingMethodContext;
|
||||
AllocationInfo(const ExplodedNode *InN,
|
||||
const MemRegion *InR,
|
||||
const LocationContext *InInterestingMethodContext) :
|
||||
N(InN), R(InR), InterestingMethodContext(InInterestingMethodContext) {}
|
||||
const StackFrame *InterestingMethodStackFrame;
|
||||
AllocationInfo(const ExplodedNode *InN, const MemRegion *InR,
|
||||
const StackFrame *InterestingMethodStackFrame)
|
||||
: N(InN), R(InR),
|
||||
InterestingMethodStackFrame(InterestingMethodStackFrame) {}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
|
|
@ -616,15 +613,15 @@ static AllocationInfo GetAllocationSite(ProgramStateManager &StateMgr,
|
|||
const ExplodedNode *AllocationNode = N;
|
||||
const ExplodedNode *AllocationNodeInCurrentOrParentContext = N;
|
||||
const MemRegion *FirstBinding = nullptr;
|
||||
const LocationContext *LeakContext = N->getLocationContext();
|
||||
const StackFrame *LeakStackFrame = N->getStackFrame();
|
||||
|
||||
// The location context of the init method called on the leaked object, if
|
||||
// The stack frame of the init method called on the leaked object, if
|
||||
// available.
|
||||
const LocationContext *InitMethodContext = nullptr;
|
||||
const StackFrame *InitMethodStackFrame = nullptr;
|
||||
|
||||
while (N) {
|
||||
ProgramStateRef St = N->getState();
|
||||
const LocationContext *NContext = N->getLocationContext();
|
||||
const StackFrame *NStackFrame = N->getStackFrame();
|
||||
|
||||
if (!getRefBinding(St, Sym))
|
||||
break;
|
||||
|
|
@ -637,7 +634,7 @@ static AllocationInfo GetAllocationSite(ProgramStateManager &StateMgr,
|
|||
// Do not show local variables belonging to a function other than
|
||||
// where the error is reported.
|
||||
if (const auto *MR = R->getMemorySpaceAs<StackSpaceRegion>(St))
|
||||
if (MR->getStackFrame() == LeakContext->getStackFrame())
|
||||
if (MR->getStackFrame() == LeakStackFrame)
|
||||
FirstBinding = R;
|
||||
}
|
||||
|
||||
|
|
@ -651,19 +648,20 @@ static AllocationInfo GetAllocationSite(ProgramStateManager &StateMgr,
|
|||
// the case where an allocation happens in a block that captures a reference
|
||||
// to it and that reference is overwritten/dropped by another call to
|
||||
// the block.
|
||||
if (NContext == LeakContext || NContext->isParentOf(LeakContext))
|
||||
if (NStackFrame == LeakStackFrame ||
|
||||
NStackFrame->isParentOf(LeakStackFrame))
|
||||
AllocationNodeInCurrentOrParentContext = N;
|
||||
|
||||
// Find the last init that was called on the given symbol and store the
|
||||
// init method's location context.
|
||||
if (!InitMethodContext)
|
||||
// init method's stack frame.
|
||||
if (!InitMethodStackFrame)
|
||||
if (auto CEP = N->getLocation().getAs<CallEnter>()) {
|
||||
const Stmt *CE = CEP->getCallExpr();
|
||||
if (const auto *ME = dyn_cast_or_null<ObjCMessageExpr>(CE)) {
|
||||
if (const Expr *RecExpr = ME->getInstanceReceiver()) {
|
||||
SVal RecV = St->getSVal(RecExpr, NContext);
|
||||
SVal RecV = St->getSVal(RecExpr, NStackFrame);
|
||||
if (ME->getMethodFamily() == OMF_init && RecV.getAsSymbol() == Sym)
|
||||
InitMethodContext = CEP->getCalleeContext();
|
||||
InitMethodStackFrame = CEP->getCalleeStackFrame();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -673,13 +671,13 @@ static AllocationInfo GetAllocationSite(ProgramStateManager &StateMgr,
|
|||
|
||||
// If we are reporting a leak of the object that was allocated with alloc,
|
||||
// mark its init method as interesting.
|
||||
const LocationContext *InterestingMethodContext = nullptr;
|
||||
if (InitMethodContext) {
|
||||
const StackFrame *InterestingMethodStackFrame = nullptr;
|
||||
if (InitMethodStackFrame) {
|
||||
const ProgramPoint AllocPP = AllocationNode->getLocation();
|
||||
if (std::optional<StmtPoint> SP = AllocPP.getAs<StmtPoint>())
|
||||
if (const ObjCMessageExpr *ME = SP->getStmtAs<ObjCMessageExpr>())
|
||||
if (ME->getMethodFamily() == OMF_alloc)
|
||||
InterestingMethodContext = InitMethodContext;
|
||||
InterestingMethodStackFrame = InitMethodStackFrame;
|
||||
}
|
||||
|
||||
// If allocation happened in a function different from the leak node context,
|
||||
|
|
@ -687,12 +685,11 @@ static AllocationInfo GetAllocationSite(ProgramStateManager &StateMgr,
|
|||
assert(N && "Could not find allocation node");
|
||||
|
||||
if (AllocationNodeInCurrentOrParentContext &&
|
||||
AllocationNodeInCurrentOrParentContext->getLocationContext() !=
|
||||
LeakContext)
|
||||
AllocationNodeInCurrentOrParentContext->getStackFrame() != LeakStackFrame)
|
||||
FirstBinding = nullptr;
|
||||
|
||||
return AllocationInfo(AllocationNodeInCurrentOrParentContext, FirstBinding,
|
||||
InterestingMethodContext);
|
||||
InterestingMethodStackFrame);
|
||||
}
|
||||
|
||||
PathDiagnosticPieceRef
|
||||
|
|
@ -809,7 +806,7 @@ void RefLeakReport::deriveParamLocation(CheckerContext &Ctx) {
|
|||
PathDiagnosticLocation::create(PDecl, SMgr);
|
||||
Location = ParamLocation;
|
||||
UniqueingLocation = ParamLocation;
|
||||
UniqueingDecl = Ctx.getLocationContext()->getDecl();
|
||||
UniqueingDecl = Ctx.getStackFrame()->getDecl();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -832,7 +829,7 @@ void RefLeakReport::deriveAllocLocation(CheckerContext &Ctx) {
|
|||
|
||||
AllocNode = AllocI.N;
|
||||
AllocFirstBinding = AllocI.R;
|
||||
markInteresting(AllocI.InterestingMethodContext);
|
||||
markInteresting(AllocI.InterestingMethodStackFrame);
|
||||
|
||||
// Get the SourceLocation for the allocation site.
|
||||
// FIXME: This will crash the analyzer if an allocation comes from an
|
||||
|
|
@ -846,13 +843,13 @@ void RefLeakReport::deriveAllocLocation(CheckerContext &Ctx) {
|
|||
}
|
||||
|
||||
PathDiagnosticLocation AllocLocation = PathDiagnosticLocation::createBegin(
|
||||
AllocStmt, SMgr, AllocNode->getLocationContext());
|
||||
AllocStmt, SMgr, AllocNode->getStackFrame());
|
||||
Location = AllocLocation;
|
||||
|
||||
// Set uniqieing info, which will be used for unique the bug reports. The
|
||||
// leaks should be uniqued on the allocation site.
|
||||
UniqueingLocation = AllocLocation;
|
||||
UniqueingDecl = AllocNode->getLocationContext()->getDecl();
|
||||
UniqueingDecl = AllocNode->getStackFrame()->getDecl();
|
||||
}
|
||||
|
||||
void RefLeakReport::createDescription(CheckerContext &Ctx) {
|
||||
|
|
|
|||
|
|
@ -112,8 +112,7 @@ void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS,
|
|||
OS << ", returned pointer points at index " << ConcreteIdx->getValue();
|
||||
}
|
||||
|
||||
Report->addNote(SBuf,
|
||||
{RetE, C.getSourceManager(), C.getLocationContext()});
|
||||
Report->addNote(SBuf, {RetE, C.getSourceManager(), C.getStackFrame()});
|
||||
}
|
||||
|
||||
bugreporter::trackExpressionValue(N, RetE, *Report);
|
||||
|
|
|
|||
|
|
@ -133,12 +133,12 @@ void STLAlgorithmModeling::Find(CheckerContext &C, const CallEvent &Call,
|
|||
const auto &Elem = Call.getCFGElementRef();
|
||||
auto State = C.getState();
|
||||
auto &SVB = C.getSValBuilder();
|
||||
const auto *LCtx = C.getLocationContext();
|
||||
const auto *SF = C.getStackFrame();
|
||||
|
||||
SVal RetVal = SVB.conjureSymbolVal(nullptr, Elem, LCtx, C.blockCount());
|
||||
SVal Param = State->getSVal(CE->getArg(paramNum), LCtx);
|
||||
SVal RetVal = SVB.conjureSymbolVal(nullptr, Elem, SF, C.blockCount());
|
||||
SVal Param = State->getSVal(CE->getArg(paramNum), SF);
|
||||
|
||||
auto StateFound = State->BindExpr(CE, LCtx, RetVal);
|
||||
auto StateFound = State->BindExpr(CE, SF, RetVal);
|
||||
|
||||
// If we have an iterator position for the range-begin argument then we can
|
||||
// assume that in case of successful search the position of the found element
|
||||
|
|
@ -147,7 +147,7 @@ void STLAlgorithmModeling::Find(CheckerContext &C, const CallEvent &Call,
|
|||
const auto *Pos = getIteratorPosition(State, Param);
|
||||
if (Pos) {
|
||||
StateFound = createIteratorPosition(StateFound, RetVal, Pos->getContainer(),
|
||||
Elem, LCtx, C.blockCount());
|
||||
Elem, SF, C.blockCount());
|
||||
const auto *NewPos = getIteratorPosition(StateFound, RetVal);
|
||||
assert(NewPos && "Failed to create new iterator position.");
|
||||
|
||||
|
|
@ -160,7 +160,7 @@ void STLAlgorithmModeling::Find(CheckerContext &C, const CallEvent &Call,
|
|||
StateFound = StateFound->assume(GreaterOrEqual.castAs<DefinedSVal>(), true);
|
||||
}
|
||||
|
||||
Param = State->getSVal(CE->getArg(paramNum + 1), LCtx);
|
||||
Param = State->getSVal(CE->getArg(paramNum + 1), SF);
|
||||
|
||||
// If we have an iterator position for the range-end argument then we can
|
||||
// assume that in case of successful search the position of the found element
|
||||
|
|
@ -169,7 +169,7 @@ void STLAlgorithmModeling::Find(CheckerContext &C, const CallEvent &Call,
|
|||
Pos = getIteratorPosition(State, Param);
|
||||
if (Pos) {
|
||||
StateFound = createIteratorPosition(StateFound, RetVal, Pos->getContainer(),
|
||||
Elem, LCtx, C.blockCount());
|
||||
Elem, SF, C.blockCount());
|
||||
const auto *NewPos = getIteratorPosition(StateFound, RetVal);
|
||||
assert(NewPos && "Failed to create new iterator position.");
|
||||
|
||||
|
|
@ -185,7 +185,7 @@ void STLAlgorithmModeling::Find(CheckerContext &C, const CallEvent &Call,
|
|||
C.addTransition(StateFound);
|
||||
|
||||
if (AggressiveStdFindModeling) {
|
||||
auto StateNotFound = State->BindExpr(CE, LCtx, Param);
|
||||
auto StateNotFound = State->BindExpr(CE, SF, Param);
|
||||
C.addTransition(StateNotFound);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,8 +54,8 @@ public:
|
|||
checkRegionChanges(ProgramStateRef State,
|
||||
const InvalidatedSymbols *Invalidated,
|
||||
ArrayRef<const MemRegion *> ExplicitRegions,
|
||||
ArrayRef<const MemRegion *> Regions,
|
||||
const LocationContext *LCtx, const CallEvent *Call) const;
|
||||
ArrayRef<const MemRegion *> Regions, const StackFrame *SF,
|
||||
const CallEvent *Call) const;
|
||||
void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
|
||||
const char *Sep) const override;
|
||||
void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const;
|
||||
|
|
@ -303,7 +303,7 @@ bool SmartPtrModeling::evalCall(const CallEvent &Call,
|
|||
return false;
|
||||
|
||||
const auto PtrVal = C.getSValBuilder().getConjuredHeapSymbolVal(
|
||||
Call.getCFGElementRef(), C.getLocationContext(),
|
||||
Call.getCFGElementRef(), C.getStackFrame(),
|
||||
getPointerTypeFromTemplateArg(Call, C), C.blockCount());
|
||||
|
||||
const MemRegion *ThisRegion = ThisRegionOpt->getAsRegion();
|
||||
|
|
@ -328,7 +328,7 @@ bool SmartPtrModeling::evalCall(const CallEvent &Call,
|
|||
// automatically deduced).
|
||||
auto &Engine = State->getStateManager().getOwningEngine();
|
||||
State = Engine.updateObjectsUnderConstruction(
|
||||
*ThisRegionOpt, nullptr, State, C.getLocationContext(),
|
||||
*ThisRegionOpt, nullptr, State, C.getStackFrame(),
|
||||
Call.getConstructionContext(), {});
|
||||
|
||||
// We don't leave a note here since it is guaranteed the
|
||||
|
|
@ -360,7 +360,7 @@ bool SmartPtrModeling::evalCall(const CallEvent &Call,
|
|||
|
||||
// TODO: Add a note to bug reports describing this decision.
|
||||
C.addTransition(State->BindExpr(
|
||||
Call.getOriginExpr(), C.getLocationContext(),
|
||||
Call.getOriginExpr(), C.getStackFrame(),
|
||||
C.getSValBuilder().makeZeroVal(Call.getResultType())));
|
||||
|
||||
return true;
|
||||
|
|
@ -439,8 +439,8 @@ std::pair<SVal, ProgramStateRef> SmartPtrModeling::retrieveOrConjureInnerPtrVal(
|
|||
const auto *Ptr = State->get<TrackedRegionMap>(ThisRegion);
|
||||
if (Ptr)
|
||||
return {*Ptr, State};
|
||||
auto Val = C.getSValBuilder().conjureSymbolVal(Elem, C.getLocationContext(),
|
||||
Type, C.blockCount());
|
||||
auto Val = C.getSValBuilder().conjureSymbolVal(Elem, C.getStackFrame(), Type,
|
||||
C.blockCount());
|
||||
State = State->set<TrackedRegionMap>(ThisRegion, Val);
|
||||
return {Val, State};
|
||||
}
|
||||
|
|
@ -484,7 +484,7 @@ bool SmartPtrModeling::handleComparisionOp(const CallEvent &Call,
|
|||
const auto *SecondExpr = Call.getArgExpr(1);
|
||||
|
||||
const auto *ResultExpr = Call.getOriginExpr();
|
||||
const auto *LCtx = C.getLocationContext();
|
||||
const auto *SF = C.getStackFrame();
|
||||
auto &Bldr = C.getSValBuilder();
|
||||
ProgramStateRef State = C.getState();
|
||||
|
||||
|
|
@ -504,12 +504,12 @@ bool SmartPtrModeling::handleComparisionOp(const CallEvent &Call,
|
|||
State->assume(*RetVal.getAs<DefinedOrUnknownSVal>());
|
||||
if (TrueState)
|
||||
C.addTransition(
|
||||
TrueState->BindExpr(ResultExpr, LCtx, Bldr.makeTruthVal(true)));
|
||||
TrueState->BindExpr(ResultExpr, SF, Bldr.makeTruthVal(true)));
|
||||
if (FalseState)
|
||||
C.addTransition(
|
||||
FalseState->BindExpr(ResultExpr, LCtx, Bldr.makeTruthVal(false)));
|
||||
FalseState->BindExpr(ResultExpr, SF, Bldr.makeTruthVal(false)));
|
||||
} else {
|
||||
C.addTransition(State->BindExpr(ResultExpr, LCtx, RetVal));
|
||||
C.addTransition(State->BindExpr(ResultExpr, SF, RetVal));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -529,11 +529,9 @@ bool SmartPtrModeling::handleOstreamOperator(const CallEvent &Call,
|
|||
const MemRegion *StreamThisRegion = StreamVal.getAsRegion();
|
||||
if (!StreamThisRegion)
|
||||
return false;
|
||||
State =
|
||||
State->invalidateRegions({StreamThisRegion}, Call.getCFGElementRef(),
|
||||
C.blockCount(), C.getLocationContext(), false);
|
||||
State =
|
||||
State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), StreamVal);
|
||||
State = State->invalidateRegions({StreamThisRegion}, Call.getCFGElementRef(),
|
||||
C.blockCount(), C.getStackFrame(), false);
|
||||
State = State->BindExpr(Call.getOriginExpr(), C.getStackFrame(), StreamVal);
|
||||
C.addTransition(State);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -573,7 +571,7 @@ void SmartPtrModeling::printState(raw_ostream &Out, ProgramStateRef State,
|
|||
ProgramStateRef SmartPtrModeling::checkRegionChanges(
|
||||
ProgramStateRef State, const InvalidatedSymbols *Invalidated,
|
||||
ArrayRef<const MemRegion *> ExplicitRegions,
|
||||
ArrayRef<const MemRegion *> Regions, const LocationContext *LCtx,
|
||||
ArrayRef<const MemRegion *> Regions, const StackFrame *SF,
|
||||
const CallEvent *Call) const {
|
||||
TrackedRegionMapTy RegionMap = State->get<TrackedRegionMap>();
|
||||
TrackedRegionMapTy::Factory &RegionMapFactory =
|
||||
|
|
@ -639,7 +637,7 @@ void SmartPtrModeling::handleRelease(const CallEvent &Call,
|
|||
const auto *InnerPointVal = State->get<TrackedRegionMap>(ThisRegion);
|
||||
|
||||
if (InnerPointVal) {
|
||||
State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
|
||||
State = State->BindExpr(Call.getOriginExpr(), C.getStackFrame(),
|
||||
*InnerPointVal);
|
||||
}
|
||||
|
||||
|
|
@ -723,8 +721,8 @@ void SmartPtrModeling::handleGet(const CallEvent &Call,
|
|||
SVal InnerPointerVal;
|
||||
std::tie(InnerPointerVal, State) = retrieveOrConjureInnerPtrVal(
|
||||
State, ThisRegion, Call.getCFGElementRef(), Call.getResultType(), C);
|
||||
State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
|
||||
InnerPointerVal);
|
||||
State =
|
||||
State->BindExpr(Call.getOriginExpr(), C.getStackFrame(), InnerPointerVal);
|
||||
// TODO: Add NoteTag, for how the raw pointer got using 'get' method.
|
||||
C.addTransition(State);
|
||||
}
|
||||
|
|
@ -857,20 +855,20 @@ void SmartPtrModeling::handleBoolConversion(const CallEvent &Call,
|
|||
}
|
||||
|
||||
if (State->isNull(InnerPointerVal).isConstrainedTrue()) {
|
||||
State = State->BindExpr(CallExpr, C.getLocationContext(),
|
||||
State = State->BindExpr(CallExpr, C.getStackFrame(),
|
||||
C.getSValBuilder().makeTruthVal(false));
|
||||
|
||||
C.addTransition(State);
|
||||
return;
|
||||
} else if (State->isNonNull(InnerPointerVal).isConstrainedTrue()) {
|
||||
State = State->BindExpr(CallExpr, C.getLocationContext(),
|
||||
State = State->BindExpr(CallExpr, C.getStackFrame(),
|
||||
C.getSValBuilder().makeTruthVal(true));
|
||||
|
||||
C.addTransition(State);
|
||||
return;
|
||||
} else if (move::isMovedFrom(State, ThisRegion)) {
|
||||
C.addTransition(
|
||||
State->BindExpr(CallExpr, C.getLocationContext(),
|
||||
State->BindExpr(CallExpr, C.getStackFrame(),
|
||||
C.getSValBuilder().makeZeroVal(Call.getResultType())));
|
||||
return;
|
||||
} else {
|
||||
|
|
@ -882,7 +880,7 @@ void SmartPtrModeling::handleBoolConversion(const CallEvent &Call,
|
|||
// Explicitly tracking the region as null.
|
||||
NullState = NullState->set<TrackedRegionMap>(ThisRegion, NullVal);
|
||||
|
||||
NullState = NullState->BindExpr(CallExpr, C.getLocationContext(),
|
||||
NullState = NullState->BindExpr(CallExpr, C.getStackFrame(),
|
||||
C.getSValBuilder().makeTruthVal(false));
|
||||
C.addTransition(NullState, C.getNoteTag(
|
||||
[ThisRegion](PathSensitiveBugReport &BR,
|
||||
|
|
@ -892,9 +890,8 @@ void SmartPtrModeling::handleBoolConversion(const CallEvent &Call,
|
|||
OS << " is null";
|
||||
},
|
||||
/*IsPrunable=*/true));
|
||||
NotNullState =
|
||||
NotNullState->BindExpr(CallExpr, C.getLocationContext(),
|
||||
C.getSValBuilder().makeTruthVal(true));
|
||||
NotNullState = NotNullState->BindExpr(
|
||||
CallExpr, C.getStackFrame(), C.getSValBuilder().makeTruthVal(true));
|
||||
C.addTransition(
|
||||
NotNullState,
|
||||
C.getNoteTag(
|
||||
|
|
|
|||
|
|
@ -457,8 +457,7 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
|
|||
|
||||
ExplodedNode *Node = Ctx.getPredecessor();
|
||||
|
||||
bool ExitingTopFrame =
|
||||
Ctx.getPredecessor()->getLocationContext()->inTopFrame();
|
||||
bool ExitingTopFrame = Ctx.getPredecessor()->getStackFrame()->inTopFrame();
|
||||
|
||||
if (ExitingTopFrame &&
|
||||
Node->getLocation().getTag() == ExprEngine::cleanupNodeTag() &&
|
||||
|
|
|
|||
|
|
@ -1477,10 +1477,9 @@ bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call,
|
|||
switch (Summary.getInvalidationKd()) {
|
||||
case EvalCallAsPure: {
|
||||
ProgramStateRef State = C.getState();
|
||||
const LocationContext *LC = C.getLocationContext();
|
||||
const auto *CE = cast<CallExpr>(Call.getOriginExpr());
|
||||
SVal V = C.getSValBuilder().conjureSymbolVal(Call, C.blockCount());
|
||||
State = State->BindExpr(CE, LC, V);
|
||||
State = State->BindExpr(CE, C.getStackFrame(), V);
|
||||
|
||||
C.addTransition(State);
|
||||
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ public:
|
|||
const InvalidatedSymbols *,
|
||||
ArrayRef<const MemRegion *>,
|
||||
ArrayRef<const MemRegion *> Regions,
|
||||
const LocationContext *,
|
||||
const StackFrame *,
|
||||
const CallEvent *Call) const {
|
||||
if (!Call)
|
||||
return State;
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ SVal getStreamArg(const FnDescription *Desc, const CallEvent &Call) {
|
|||
/// Create a conjured symbol return value for a call expression.
|
||||
DefinedSVal makeRetVal(CheckerContext &C, ConstCFGElementRef Elem) {
|
||||
return C.getSValBuilder()
|
||||
.conjureSymbolVal(/*symbolTag=*/nullptr, Elem, C.getLocationContext(),
|
||||
.conjureSymbolVal(/*symbolTag=*/nullptr, Elem, C.getStackFrame(),
|
||||
C.blockCount())
|
||||
.castAs<DefinedSVal>();
|
||||
}
|
||||
|
|
@ -234,7 +234,7 @@ DefinedSVal makeRetVal(CheckerContext &C, ConstCFGElementRef Elem) {
|
|||
ProgramStateRef bindAndAssumeTrue(ProgramStateRef State, CheckerContext &C,
|
||||
const CallExpr *CE, ConstCFGElementRef Elem) {
|
||||
DefinedSVal RetVal = makeRetVal(C, Elem);
|
||||
State = State->BindExpr(CE, C.getLocationContext(), RetVal);
|
||||
State = State->BindExpr(CE, C.getStackFrame(), RetVal);
|
||||
State = State->assume(RetVal, true);
|
||||
assert(State && "Assumption on new value should not fail.");
|
||||
return State;
|
||||
|
|
@ -242,7 +242,7 @@ ProgramStateRef bindAndAssumeTrue(ProgramStateRef State, CheckerContext &C,
|
|||
|
||||
ProgramStateRef bindInt(uint64_t Value, ProgramStateRef State,
|
||||
CheckerContext &C, const CallExpr *CE) {
|
||||
State = State->BindExpr(CE, C.getLocationContext(),
|
||||
State = State->BindExpr(CE, C.getStackFrame(),
|
||||
C.getSValBuilder().makeIntVal(Value, CE->getType()));
|
||||
return State;
|
||||
}
|
||||
|
|
@ -684,23 +684,23 @@ struct StreamOperationEvaluator {
|
|||
|
||||
ProgramStateRef makeAndBindRetVal(ProgramStateRef State, CheckerContext &C) {
|
||||
NonLoc RetVal = makeRetVal(C, Elem.value()).castAs<NonLoc>();
|
||||
return State->BindExpr(CE, C.getLocationContext(), RetVal);
|
||||
return State->BindExpr(CE, C.getStackFrame(), RetVal);
|
||||
}
|
||||
|
||||
ProgramStateRef bindReturnValue(ProgramStateRef State, CheckerContext &C,
|
||||
uint64_t Val) {
|
||||
return State->BindExpr(CE, C.getLocationContext(),
|
||||
return State->BindExpr(CE, C.getStackFrame(),
|
||||
SVB.makeIntVal(Val, CE->getCallReturnType(ACtx)));
|
||||
}
|
||||
|
||||
ProgramStateRef bindReturnValue(ProgramStateRef State, CheckerContext &C,
|
||||
SVal Val) {
|
||||
return State->BindExpr(CE, C.getLocationContext(), Val);
|
||||
return State->BindExpr(CE, C.getStackFrame(), Val);
|
||||
}
|
||||
|
||||
ProgramStateRef bindNullReturnValue(ProgramStateRef State,
|
||||
CheckerContext &C) {
|
||||
return State->BindExpr(CE, C.getLocationContext(),
|
||||
return State->BindExpr(CE, C.getStackFrame(),
|
||||
C.getSValBuilder().makeNullWithType(CE->getType()));
|
||||
}
|
||||
|
||||
|
|
@ -717,7 +717,7 @@ struct StreamOperationEvaluator {
|
|||
ConstraintManager::ProgramStatePair
|
||||
makeRetValAndAssumeDual(ProgramStateRef State, CheckerContext &C) {
|
||||
DefinedSVal RetVal = makeRetVal(C, Elem.value());
|
||||
State = State->BindExpr(CE, C.getLocationContext(), RetVal);
|
||||
State = State->BindExpr(CE, C.getStackFrame(), RetVal);
|
||||
return C.getConstraintManager().assumeDual(State, RetVal);
|
||||
}
|
||||
|
||||
|
|
@ -841,7 +841,7 @@ escapeByStartIndexAndCount(ProgramStateRef State, const CallEvent &Call,
|
|||
RegionAndSymbolInvalidationTraits::InvalidationKinds::
|
||||
TK_DoNotInvalidateSuperRegion;
|
||||
|
||||
const LocationContext *LCtx = Call.getLocationContext();
|
||||
const StackFrame *SF = Call.getStackFrame();
|
||||
const ASTContext &Ctx = State->getStateManager().getContext();
|
||||
SValBuilder &SVB = State->getStateManager().getSValBuilder();
|
||||
auto &RegionManager = Buffer->getMemRegionManager();
|
||||
|
|
@ -858,7 +858,7 @@ escapeByStartIndexAndCount(ProgramStateRef State, const CallEvent &Call,
|
|||
ITraits.setTrait(Element, DoNotInvalidateSuperRegion);
|
||||
}
|
||||
return State->invalidateRegions(
|
||||
EscapingVals, Call.getCFGElementRef(), BlockCount, LCtx,
|
||||
EscapingVals, Call.getCFGElementRef(), BlockCount, SF,
|
||||
/*CausesPointerEscape=*/false,
|
||||
/*InvalidatedSymbols=*/nullptr, &Call, &ITraits);
|
||||
}
|
||||
|
|
@ -869,7 +869,7 @@ static ProgramStateRef escapeArgs(ProgramStateRef State, CheckerContext &C,
|
|||
auto GetArgSVal = [&Call](int Idx) { return Call.getArgSVal(Idx); };
|
||||
auto EscapingVals = to_vector(map_range(EscapingArgs, GetArgSVal));
|
||||
State = State->invalidateRegions(EscapingVals, Call.getCFGElementRef(),
|
||||
C.blockCount(), C.getLocationContext(),
|
||||
C.blockCount(), C.getStackFrame(),
|
||||
/*CausesPointerEscape=*/false,
|
||||
/*InvalidatedSymbols=*/nullptr);
|
||||
return State;
|
||||
|
|
@ -906,10 +906,10 @@ ProgramStateRef StreamChecker::assumeNoAliasingWithStdStreams(
|
|||
const VarDecl *Var) -> ProgramStateRef {
|
||||
if (!Var)
|
||||
return State;
|
||||
const auto *LCtx = C.getLocationContext();
|
||||
const auto *SF = C.getStackFrame();
|
||||
auto &StoreMgr = C.getStoreManager();
|
||||
auto &SVB = C.getSValBuilder();
|
||||
SVal VarValue = State->getSVal(StoreMgr.getLValueVar(Var, LCtx));
|
||||
SVal VarValue = State->getSVal(StoreMgr.getLValueVar(Var, SF));
|
||||
auto NoAliasState =
|
||||
SVB.evalBinOp(State, BO_NE, RetVal, VarValue, SVB.getConditionType())
|
||||
.castAs<DefinedOrUnknownSVal>();
|
||||
|
|
@ -935,7 +935,7 @@ void StreamChecker::evalFopen(const FnDescription *Desc, const CallEvent &Call,
|
|||
SymbolRef RetSym = RetVal.getAsSymbol();
|
||||
assert(RetSym && "RetVal must be a symbol here.");
|
||||
|
||||
State = State->BindExpr(CE, C.getLocationContext(), RetVal);
|
||||
State = State->BindExpr(CE, C.getStackFrame(), RetVal);
|
||||
|
||||
// Bifurcate the state into two: one with a valid FILE* pointer, the other
|
||||
// with a NULL.
|
||||
|
|
@ -996,11 +996,11 @@ void StreamChecker::evalFreopen(const FnDescription *Desc,
|
|||
// According to the documentations, the stream is closed first
|
||||
// but any close error is ignored. The state changes to (or remains) opened.
|
||||
ProgramStateRef StateRetNotNull =
|
||||
State->BindExpr(CE, C.getLocationContext(), *StreamVal);
|
||||
State->BindExpr(CE, C.getStackFrame(), *StreamVal);
|
||||
// Generate state for NULL return value.
|
||||
// Stream switches to OpenFailed state.
|
||||
ProgramStateRef StateRetNull =
|
||||
State->BindExpr(CE, C.getLocationContext(),
|
||||
State->BindExpr(CE, C.getStackFrame(),
|
||||
C.getSValBuilder().makeNullWithType(CE->getType()));
|
||||
|
||||
StateRetNotNull =
|
||||
|
|
@ -1189,7 +1189,7 @@ void StreamChecker::evalFreadFwrite(const FnDescription *Desc,
|
|||
// If we know the state to be FEOF at fread, do not add a success state.
|
||||
if (!IsFread || !E.isStreamEof()) {
|
||||
ProgramStateRef StateNotFailed =
|
||||
State->BindExpr(E.CE, C.getLocationContext(), *NMembVal);
|
||||
State->BindExpr(E.CE, C.getStackFrame(), *NMembVal);
|
||||
StateNotFailed =
|
||||
E.setStreamState(StateNotFailed, StreamState::getOpened(Desc));
|
||||
C.addTransition(StateNotFailed);
|
||||
|
|
@ -1202,7 +1202,7 @@ void StreamChecker::evalFreadFwrite(const FnDescription *Desc,
|
|||
|
||||
NonLoc RetVal = makeRetVal(C, E.Elem.value()).castAs<NonLoc>();
|
||||
ProgramStateRef StateFailed =
|
||||
State->BindExpr(E.CE, C.getLocationContext(), RetVal);
|
||||
State->BindExpr(E.CE, C.getStackFrame(), RetVal);
|
||||
StateFailed = E.assumeBinOpNN(StateFailed, BO_LT, RetVal, *NMembVal);
|
||||
if (!StateFailed)
|
||||
return;
|
||||
|
|
@ -1237,7 +1237,7 @@ void StreamChecker::evalFgetx(const FnDescription *Desc, const CallEvent &Call,
|
|||
// Generate a transition for the success state of `fgetc`.
|
||||
NonLoc RetVal = makeRetVal(C, E.Elem.value()).castAs<NonLoc>();
|
||||
ProgramStateRef StateNotFailed =
|
||||
State->BindExpr(E.CE, C.getLocationContext(), RetVal);
|
||||
State->BindExpr(E.CE, C.getStackFrame(), RetVal);
|
||||
// The returned 'unsigned char' of `fgetc` is converted to 'int',
|
||||
// so we need to check if it is in range [0, 255].
|
||||
StateNotFailed = StateNotFailed->assumeInclusiveRange(
|
||||
|
|
@ -1255,7 +1255,7 @@ void StreamChecker::evalFgetx(const FnDescription *Desc, const CallEvent &Call,
|
|||
if (!GetBuf)
|
||||
return;
|
||||
ProgramStateRef StateNotFailed =
|
||||
State->BindExpr(E.CE, C.getLocationContext(), *GetBuf);
|
||||
State->BindExpr(E.CE, C.getStackFrame(), *GetBuf);
|
||||
StateNotFailed =
|
||||
E.setStreamState(StateNotFailed, StreamState::getOpened(Desc));
|
||||
C.addTransition(StateNotFailed);
|
||||
|
|
@ -1294,7 +1294,7 @@ void StreamChecker::evalFputx(const FnDescription *Desc, const CallEvent &Call,
|
|||
if (!PutVal)
|
||||
return;
|
||||
ProgramStateRef StateNotFailed =
|
||||
State->BindExpr(E.CE, C.getLocationContext(), *PutVal);
|
||||
State->BindExpr(E.CE, C.getStackFrame(), *PutVal);
|
||||
StateNotFailed =
|
||||
E.setStreamState(StateNotFailed, StreamState::getOpened(Desc));
|
||||
C.addTransition(StateNotFailed);
|
||||
|
|
@ -1302,7 +1302,7 @@ void StreamChecker::evalFputx(const FnDescription *Desc, const CallEvent &Call,
|
|||
// Generate a transition for the success state of `fputs`.
|
||||
NonLoc RetVal = makeRetVal(C, E.Elem.value()).castAs<NonLoc>();
|
||||
ProgramStateRef StateNotFailed =
|
||||
State->BindExpr(E.CE, C.getLocationContext(), RetVal);
|
||||
State->BindExpr(E.CE, C.getStackFrame(), RetVal);
|
||||
StateNotFailed =
|
||||
E.assumeBinOpNN(StateNotFailed, BO_GE, RetVal, E.getZeroVal(Call));
|
||||
if (!StateNotFailed)
|
||||
|
|
@ -1335,7 +1335,7 @@ void StreamChecker::evalFprintf(const FnDescription *Desc,
|
|||
return;
|
||||
|
||||
NonLoc RetVal = makeRetVal(C, E.Elem.value()).castAs<NonLoc>();
|
||||
State = State->BindExpr(E.CE, C.getLocationContext(), RetVal);
|
||||
State = State->BindExpr(E.CE, C.getStackFrame(), RetVal);
|
||||
auto Cond =
|
||||
E.SVB
|
||||
.evalBinOp(State, BO_GE, RetVal, E.SVB.makeZeroVal(E.ACtx.IntTy),
|
||||
|
|
@ -1381,7 +1381,7 @@ void StreamChecker::evalFscanf(const FnDescription *Desc, const CallEvent &Call,
|
|||
if (!E.isStreamEof()) {
|
||||
NonLoc RetVal = makeRetVal(C, E.Elem.value()).castAs<NonLoc>();
|
||||
ProgramStateRef StateNotFailed =
|
||||
State->BindExpr(E.CE, C.getLocationContext(), RetVal);
|
||||
State->BindExpr(E.CE, C.getStackFrame(), RetVal);
|
||||
StateNotFailed =
|
||||
E.assumeBinOpNN(StateNotFailed, BO_GE, RetVal, E.getZeroVal(Call));
|
||||
if (!StateNotFailed)
|
||||
|
|
@ -1495,8 +1495,8 @@ void StreamChecker::evalGetdelim(const FnDescription *Desc,
|
|||
StateFailed, StreamState::getOpened(Desc, NewES, !NewES.isFEof()));
|
||||
// On failure, the content of the buffer is undefined.
|
||||
if (auto NewLinePtr = getPointeeVal(Call.getArgSVal(0), State))
|
||||
StateFailed = StateFailed->bindLoc(*NewLinePtr, UndefinedVal(),
|
||||
C.getLocationContext());
|
||||
StateFailed =
|
||||
StateFailed->bindLoc(*NewLinePtr, UndefinedVal(), C.getStackFrame());
|
||||
C.addTransition(StateFailed, E.getFailureNoteTag(this, C));
|
||||
}
|
||||
|
||||
|
|
@ -1603,7 +1603,7 @@ void StreamChecker::evalFtell(const FnDescription *Desc, const CallEvent &Call,
|
|||
|
||||
NonLoc RetVal = makeRetVal(C, E.Elem.value()).castAs<NonLoc>();
|
||||
ProgramStateRef StateNotFailed =
|
||||
State->BindExpr(E.CE, C.getLocationContext(), RetVal);
|
||||
State->BindExpr(E.CE, C.getStackFrame(), RetVal);
|
||||
StateNotFailed =
|
||||
E.assumeBinOpNN(StateNotFailed, BO_GE, RetVal, E.getZeroVal(Call));
|
||||
if (!StateNotFailed)
|
||||
|
|
@ -1771,7 +1771,7 @@ void StreamChecker::evalFileno(const FnDescription *Desc, const CallEvent &Call,
|
|||
return;
|
||||
|
||||
NonLoc RetVal = makeRetVal(C, E.Elem.value()).castAs<NonLoc>();
|
||||
State = State->BindExpr(E.CE, C.getLocationContext(), RetVal);
|
||||
State = State->BindExpr(E.CE, C.getStackFrame(), RetVal);
|
||||
State = E.assumeBinOpNN(State, BO_GE, RetVal, E.getZeroVal(Call));
|
||||
if (!State)
|
||||
return;
|
||||
|
|
@ -1868,8 +1868,7 @@ public:
|
|||
if (!S)
|
||||
return nullptr;
|
||||
Satisfied = true;
|
||||
PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
|
||||
N->getLocationContext());
|
||||
PathDiagnosticLocation Pos(S, BRC.getSourceManager(), N->getStackFrame());
|
||||
llvm::StringLiteral Msg = "Stream is closed here";
|
||||
return std::make_shared<PathDiagnosticEventPiece>(Pos, Msg);
|
||||
}
|
||||
|
|
@ -2034,15 +2033,13 @@ StreamChecker::reportLeaks(const SmallVector<SymbolRef, 2> &LeakedSyms,
|
|||
PathDiagnosticLocation LocUsedForUniqueing;
|
||||
if (const Stmt *StreamStmt = StreamOpenNode->getStmtForDiagnostics())
|
||||
LocUsedForUniqueing = PathDiagnosticLocation::createBegin(
|
||||
StreamStmt, C.getSourceManager(),
|
||||
StreamOpenNode->getLocationContext());
|
||||
StreamStmt, C.getSourceManager(), StreamOpenNode->getStackFrame());
|
||||
|
||||
std::unique_ptr<PathSensitiveBugReport> R =
|
||||
std::make_unique<PathSensitiveBugReport>(
|
||||
BT_ResourceLeak,
|
||||
"Opened stream never closed. Potential resource leak.", Err,
|
||||
LocUsedForUniqueing,
|
||||
StreamOpenNode->getLocationContext()->getDecl());
|
||||
LocUsedForUniqueing, StreamOpenNode->getStackFrame()->getDecl());
|
||||
R->markInteresting(LeakSym);
|
||||
R->addVisitor<NoStreamStateChangeVisitor>(LeakSym, this);
|
||||
C.emitReport(std::move(R));
|
||||
|
|
|
|||
|
|
@ -44,9 +44,8 @@ void taint::dumpTaint(ProgramStateRef State) {
|
|||
}
|
||||
|
||||
ProgramStateRef taint::addTaint(ProgramStateRef State, const Expr *E,
|
||||
const LocationContext *LCtx,
|
||||
TaintTagType Kind) {
|
||||
return addTaint(State, State->getSVal(E, LCtx), Kind);
|
||||
const StackFrame *SF, TaintTagType Kind) {
|
||||
return addTaint(State, State->getSVal(E, SF), Kind);
|
||||
}
|
||||
|
||||
ProgramStateRef taint::addTaint(ProgramStateRef State, SVal V,
|
||||
|
|
@ -146,8 +145,8 @@ ProgramStateRef taint::addPartialTaint(ProgramStateRef State,
|
|||
}
|
||||
|
||||
bool taint::isTainted(ProgramStateRef State, const Expr *E,
|
||||
const LocationContext *LCtx, TaintTagType Kind) {
|
||||
return !getTaintedSymbolsImpl(State, E, LCtx, Kind, /*ReturnFirstOnly=*/true)
|
||||
const StackFrame *SF, TaintTagType Kind) {
|
||||
return !getTaintedSymbolsImpl(State, E, SF, Kind, /*ReturnFirstOnly=*/true)
|
||||
.empty();
|
||||
}
|
||||
|
||||
|
|
@ -169,9 +168,9 @@ bool taint::isTainted(ProgramStateRef State, SymbolRef Sym, TaintTagType Kind) {
|
|||
|
||||
std::vector<SymbolRef> taint::getTaintedSymbols(ProgramStateRef State,
|
||||
const Expr *E,
|
||||
const LocationContext *LCtx,
|
||||
const StackFrame *SF,
|
||||
TaintTagType Kind) {
|
||||
return getTaintedSymbolsImpl(State, E, LCtx, Kind,
|
||||
return getTaintedSymbolsImpl(State, E, SF, Kind,
|
||||
/*ReturnFirstOnly=*/false);
|
||||
}
|
||||
|
||||
|
|
@ -194,10 +193,10 @@ std::vector<SymbolRef> taint::getTaintedSymbols(ProgramStateRef State,
|
|||
|
||||
std::vector<SymbolRef> taint::getTaintedSymbolsImpl(ProgramStateRef State,
|
||||
const Expr *E,
|
||||
const LocationContext *LCtx,
|
||||
const StackFrame *SF,
|
||||
TaintTagType Kind,
|
||||
bool returnFirstOnly) {
|
||||
SVal val = State->getSVal(E, LCtx);
|
||||
SVal val = State->getSVal(E, SF);
|
||||
return getTaintedSymbolsImpl(State, val, Kind, returnFirstOnly);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ void TaintTesterChecker::checkPostStmt(const Expr *E,
|
|||
if (!State)
|
||||
return;
|
||||
|
||||
if (isTainted(State, E, C.getLocationContext())) {
|
||||
if (isTainted(State, E, C.getStackFrame())) {
|
||||
if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
|
||||
auto report = std::make_unique<PathSensitiveBugReport>(BT, "tainted", N);
|
||||
report->addRange(E->getSourceRange());
|
||||
|
|
|
|||
|
|
@ -67,8 +67,8 @@ public:
|
|||
|
||||
void CallDumper::checkPreCall(const CallEvent &Call, CheckerContext &C) const {
|
||||
unsigned Indentation = 0;
|
||||
for (const LocationContext *LC = C.getLocationContext()->getParent();
|
||||
LC != nullptr; LC = LC->getParent())
|
||||
for (const StackFrame *SF = C.getStackFrame()->getParent(); SF != nullptr;
|
||||
SF = SF->getParent())
|
||||
++Indentation;
|
||||
|
||||
// It is mildly evil to print directly to llvm::outs() rather than emitting
|
||||
|
|
@ -84,8 +84,8 @@ void CallDumper::checkPostCall(const CallEvent &Call, CheckerContext &C) const {
|
|||
return;
|
||||
|
||||
unsigned Indentation = 0;
|
||||
for (const LocationContext *LC = C.getLocationContext()->getParent();
|
||||
LC != nullptr; LC = LC->getParent())
|
||||
for (const StackFrame *SF = C.getStackFrame()->getParent(); SF != nullptr;
|
||||
SF = SF->getParent())
|
||||
++Indentation;
|
||||
|
||||
// It is mildly evil to print directly to llvm::outs() rather than emitting
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ public:
|
|||
|
||||
const FunctionDecl *
|
||||
UnconditionalVAArgChecker::getCurrentFunction(CheckerContext &C) {
|
||||
const Decl *FD = C.getLocationContext()->getDecl();
|
||||
const Decl *FD = C.getStackFrame()->getDecl();
|
||||
return dyn_cast_if_present<FunctionDecl>(FD);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,10 +31,10 @@ class UndefBranchChecker : public Checker<check::BranchCondition> {
|
|||
|
||||
struct FindUndefExpr {
|
||||
ProgramStateRef St;
|
||||
const LocationContext *LCtx;
|
||||
const StackFrame *SF;
|
||||
|
||||
FindUndefExpr(ProgramStateRef S, const LocationContext *L)
|
||||
: St(std::move(S)), LCtx(L) {}
|
||||
FindUndefExpr(ProgramStateRef S, const StackFrame *SF)
|
||||
: St(std::move(S)), SF(SF) {}
|
||||
|
||||
const Expr *FindExpr(const Expr *Ex) {
|
||||
if (!MatchesCriteria(Ex))
|
||||
|
|
@ -49,7 +49,7 @@ class UndefBranchChecker : public Checker<check::BranchCondition> {
|
|||
}
|
||||
|
||||
bool MatchesCriteria(const Expr *Ex) {
|
||||
return St->getSVal(Ex, LCtx).isUndef();
|
||||
return St->getSVal(Ex, SF).isUndef();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -97,7 +97,7 @@ void UndefBranchChecker::checkBranchCondition(const Stmt *Condition,
|
|||
if (PS->getStmt() == Ex)
|
||||
St = PrevN->getState();
|
||||
|
||||
FindUndefExpr FindIt(St, Ctx.getLocationContext());
|
||||
FindUndefExpr FindIt(St, Ctx.getStackFrame());
|
||||
Ex = FindIt.FindExpr(Ex);
|
||||
|
||||
// Emit the bug report.
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ UndefinedArraySubscriptChecker::checkPreStmt(const ArraySubscriptExpr *A,
|
|||
|
||||
// Sema generates anonymous array variables for copying array struct fields.
|
||||
// Don't warn if we're in an implicitly-generated constructor.
|
||||
const Decl *D = C.getLocationContext()->getDecl();
|
||||
const Decl *D = C.getStackFrame()->getDecl();
|
||||
if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D))
|
||||
if (Ctor->isDefaulted())
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -133,8 +133,8 @@ static bool hasUnguardedAccess(const FieldDecl *FD, ProgramStateRef State);
|
|||
void UninitializedObjectChecker::checkEndFunction(
|
||||
const ReturnStmt *RS, CheckerContext &Context) const {
|
||||
|
||||
const auto *CtorDecl = dyn_cast_or_null<CXXConstructorDecl>(
|
||||
Context.getLocationContext()->getDecl());
|
||||
const auto *CtorDecl =
|
||||
dyn_cast_or_null<CXXConstructorDecl>(Context.getStackFrame()->getDecl());
|
||||
if (!CtorDecl)
|
||||
return;
|
||||
|
||||
|
|
@ -175,7 +175,7 @@ void UninitializedObjectChecker::checkEndFunction(
|
|||
const Expr *CallSite = Context.getStackFrame()->getCallSite();
|
||||
if (CallSite)
|
||||
LocUsedForUniqueing = PathDiagnosticLocation::createBegin(
|
||||
CallSite, Context.getSourceManager(), Node->getLocationContext());
|
||||
CallSite, Context.getSourceManager(), Node->getStackFrame());
|
||||
|
||||
// For Plist consumers that don't support notes just yet, we'll convert notes
|
||||
// to warnings.
|
||||
|
|
@ -184,7 +184,7 @@ void UninitializedObjectChecker::checkEndFunction(
|
|||
|
||||
auto Report = std::make_unique<PathSensitiveBugReport>(
|
||||
BT_uninitField, Pair.second, Node, LocUsedForUniqueing,
|
||||
Node->getLocationContext()->getDecl());
|
||||
Node->getStackFrame()->getDecl());
|
||||
Context.emitReport(std::move(Report));
|
||||
}
|
||||
return;
|
||||
|
|
@ -198,7 +198,7 @@ void UninitializedObjectChecker::checkEndFunction(
|
|||
|
||||
auto Report = std::make_unique<PathSensitiveBugReport>(
|
||||
BT_uninitField, WarningOS.str(), Node, LocUsedForUniqueing,
|
||||
Node->getLocationContext()->getDecl());
|
||||
Node->getStackFrame()->getDecl());
|
||||
|
||||
for (const auto &Pair : UninitFields) {
|
||||
Report->addNote(Pair.second,
|
||||
|
|
@ -492,11 +492,11 @@ static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor,
|
|||
if (!CurrRegion)
|
||||
return false;
|
||||
|
||||
const LocationContext *LC = Context.getLocationContext();
|
||||
while ((LC = LC->getParent())) {
|
||||
const StackFrame *SF = Context.getStackFrame();
|
||||
while ((SF = SF->getParent())) {
|
||||
|
||||
// If \p Ctor was called by another constructor.
|
||||
const auto *OtherCtor = dyn_cast<CXXConstructorDecl>(LC->getDecl());
|
||||
const auto *OtherCtor = dyn_cast<CXXConstructorDecl>(SF->getDecl());
|
||||
if (!OtherCtor)
|
||||
continue;
|
||||
|
||||
|
|
|
|||
|
|
@ -57,22 +57,22 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
|
|||
const Decl *D = nullptr;
|
||||
CFG *C = nullptr;
|
||||
const ParentMap *PM = nullptr;
|
||||
const LocationContext *LC = nullptr;
|
||||
const StackFrame *SF = nullptr;
|
||||
// Iterate over ExplodedGraph
|
||||
for (const ExplodedNode &N : G.nodes()) {
|
||||
const ProgramPoint &P = N.getLocation();
|
||||
LC = P.getLocationContext();
|
||||
if (!LC->inTopFrame())
|
||||
SF = P.getStackFrame();
|
||||
if (!SF->inTopFrame())
|
||||
continue;
|
||||
|
||||
if (!D)
|
||||
D = LC->getAnalysisDeclContext()->getDecl();
|
||||
D = SF->getAnalysisDeclContext()->getDecl();
|
||||
|
||||
// Save the CFG if we don't have it already
|
||||
if (!C)
|
||||
C = LC->getAnalysisDeclContext()->getUnoptimizedCFG();
|
||||
C = SF->getAnalysisDeclContext()->getUnoptimizedCFG();
|
||||
if (!PM)
|
||||
PM = &LC->getParentMap();
|
||||
PM = &SF->getParentMap();
|
||||
|
||||
if (std::optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) {
|
||||
const CFGBlock *CB = BE->getBlock();
|
||||
|
|
@ -155,7 +155,7 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
|
|||
if (isa<DoStmt>(Parent))
|
||||
continue;
|
||||
SR = S->getSourceRange();
|
||||
DL = PathDiagnosticLocation::createBegin(S, B.getSourceManager(), LC);
|
||||
DL = PathDiagnosticLocation::createBegin(S, B.getSourceManager(), SF);
|
||||
SL = DL.asLocation();
|
||||
if (SR.isInvalid() || !SL.isValid())
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@ void VAListChecker::checkDeadSymbols(SymbolReaper &SR,
|
|||
const ExplodedNode *
|
||||
VAListChecker::getStartCallSite(const ExplodedNode *N,
|
||||
const MemRegion *Reg) const {
|
||||
const LocationContext *LeakContext = N->getLocationContext();
|
||||
const StackFrame *LeakSF = N->getStackFrame();
|
||||
const ExplodedNode *StartCallNode = N;
|
||||
|
||||
bool SeenInitializedState = false;
|
||||
|
|
@ -247,8 +247,7 @@ VAListChecker::getStartCallSite(const ExplodedNode *N,
|
|||
} else if (SeenInitializedState) {
|
||||
break;
|
||||
}
|
||||
const LocationContext *NContext = N->getLocationContext();
|
||||
if (NContext == LeakContext || NContext->isParentOf(LeakContext))
|
||||
if (N->getStackFrame() == LeakSF || N->getStackFrame()->isParentOf(LeakSF))
|
||||
StartCallNode = N;
|
||||
N = N->pred_empty() ? nullptr : *(N->pred_begin());
|
||||
}
|
||||
|
|
@ -276,7 +275,7 @@ void VAListChecker::reportLeaked(const RegionVector &Leaked, StringRef Msg1,
|
|||
|
||||
if (const Stmt *StartCallStmt = StartNode->getStmtForDiagnostics())
|
||||
LocUsedForUniqueing = PathDiagnosticLocation::createBegin(
|
||||
StartCallStmt, C.getSourceManager(), StartNode->getLocationContext());
|
||||
StartCallStmt, C.getSourceManager(), StartNode->getStackFrame());
|
||||
|
||||
SmallString<100> Buf;
|
||||
llvm::raw_svector_ostream OS(Buf);
|
||||
|
|
@ -288,7 +287,7 @@ void VAListChecker::reportLeaked(const RegionVector &Leaked, StringRef Msg1,
|
|||
|
||||
auto R = std::make_unique<PathSensitiveBugReport>(
|
||||
LeakBug, OS.str(), N, LocUsedForUniqueing,
|
||||
StartNode->getLocationContext()->getDecl());
|
||||
StartNode->getStackFrame()->getDecl());
|
||||
R->markInteresting(Reg);
|
||||
R->addVisitor(std::make_unique<VAListBugVisitor>(Reg, true));
|
||||
C.emitReport(std::move(R));
|
||||
|
|
@ -413,8 +412,7 @@ PathDiagnosticPieceRef VAListChecker::VAListBugVisitor::VisitNode(
|
|||
if (Msg.empty())
|
||||
return nullptr;
|
||||
|
||||
PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
|
||||
N->getLocationContext());
|
||||
PathDiagnosticLocation Pos(S, BRC.getSourceManager(), N->getStackFrame());
|
||||
return std::make_shared<PathDiagnosticEventPiece>(Pos, Msg, true);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -296,9 +296,8 @@ void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
|
|||
|
||||
// VLASizeChecker is responsible for defining the extent of the array.
|
||||
if (VD) {
|
||||
State =
|
||||
setDynamicExtent(State, State->getRegion(VD, C.getLocationContext()),
|
||||
ArraySize.castAs<NonLoc>());
|
||||
State = setDynamicExtent(State, State->getRegion(VD, C.getStackFrame()),
|
||||
ArraySize.castAs<NonLoc>());
|
||||
}
|
||||
|
||||
// Remember our assumptions!
|
||||
|
|
|
|||
|
|
@ -158,17 +158,16 @@ void VforkChecker::checkPostCall(const CallEvent &Call,
|
|||
return;
|
||||
|
||||
// Get assigned variable.
|
||||
const ParentMap &PM = C.getLocationContext()->getParentMap();
|
||||
const ParentMap &PM = C.getStackFrame()->getParentMap();
|
||||
const Stmt *P = PM.getParentIgnoreParenCasts(Call.getOriginExpr());
|
||||
const VarDecl *LhsDecl;
|
||||
std::tie(LhsDecl, std::ignore) = parseAssignment(P);
|
||||
|
||||
// Get assigned memory region.
|
||||
MemRegionManager &M = C.getStoreManager().getRegionManager();
|
||||
const MemRegion *LhsDeclReg =
|
||||
LhsDecl
|
||||
? M.getVarRegion(LhsDecl, C.getLocationContext())
|
||||
: (const MemRegion *)VFORK_RESULT_NONE;
|
||||
const MemRegion *LhsDeclReg = LhsDecl
|
||||
? M.getVarRegion(LhsDecl, C.getStackFrame())
|
||||
: (const MemRegion *)VFORK_RESULT_NONE;
|
||||
|
||||
// Parent branch gets nonzero return value (according to manpage).
|
||||
ProgramStateRef ParentState, ChildState;
|
||||
|
|
|
|||
|
|
@ -177,8 +177,8 @@ void VirtualCallChecker::checkPreCall(const CallEvent &Call,
|
|||
|
||||
void VirtualCallChecker::registerCtorDtorCallInState(bool IsBeginFunction,
|
||||
CheckerContext &C) const {
|
||||
const auto *LCtx = C.getLocationContext();
|
||||
const auto *MD = dyn_cast_or_null<CXXMethodDecl>(LCtx->getDecl());
|
||||
const auto *SF = C.getStackFrame();
|
||||
const auto *MD = dyn_cast_or_null<CXXMethodDecl>(SF->getDecl());
|
||||
if (!MD)
|
||||
return;
|
||||
|
||||
|
|
@ -187,8 +187,7 @@ void VirtualCallChecker::registerCtorDtorCallInState(bool IsBeginFunction,
|
|||
|
||||
// Enter a constructor, set the corresponding memregion be true.
|
||||
if (isa<CXXConstructorDecl>(MD)) {
|
||||
auto ThiSVal =
|
||||
State->getSVal(SVB.getCXXThis(MD, LCtx->getStackFrame()));
|
||||
auto ThiSVal = State->getSVal(SVB.getCXXThis(MD, SF));
|
||||
const MemRegion *Reg = ThiSVal.getAsRegion();
|
||||
if (IsBeginFunction)
|
||||
State = State->set<CtorDtorMap>(Reg, ObjectState::CtorCalled);
|
||||
|
|
@ -201,8 +200,7 @@ void VirtualCallChecker::registerCtorDtorCallInState(bool IsBeginFunction,
|
|||
|
||||
// Enter a Destructor, set the corresponding memregion be true.
|
||||
if (isa<CXXDestructorDecl>(MD)) {
|
||||
auto ThiSVal =
|
||||
State->getSVal(SVB.getCXXThis(MD, LCtx->getStackFrame()));
|
||||
auto ThiSVal = State->getSVal(SVB.getCXXThis(MD, SF));
|
||||
const MemRegion *Reg = ThiSVal.getAsRegion();
|
||||
if (IsBeginFunction)
|
||||
State = State->set<CtorDtorMap>(Reg, ObjectState::DtorCalled);
|
||||
|
|
|
|||
|
|
@ -202,13 +202,13 @@ void InvalidPtrChecker::postPreviousReturnInvalidatingCall(
|
|||
});
|
||||
}
|
||||
|
||||
const LocationContext *LCtx = C.getLocationContext();
|
||||
const StackFrame *SF = C.getStackFrame();
|
||||
const auto *CE = cast<CallExpr>(Call.getOriginExpr());
|
||||
|
||||
// Function call will return a pointer to the new symbolic region.
|
||||
DefinedOrUnknownSVal RetVal =
|
||||
C.getSValBuilder().conjureSymbolVal(Call, C.blockCount());
|
||||
State = State->BindExpr(CE, LCtx, RetVal);
|
||||
State = State->BindExpr(CE, SF, RetVal);
|
||||
|
||||
const auto *SymRegOfRetVal =
|
||||
dyn_cast_or_null<SymbolicRegion>(RetVal.getAsRegion());
|
||||
|
|
@ -316,13 +316,13 @@ void InvalidPtrChecker::checkBeginFunction(CheckerContext &C) const {
|
|||
if (!C.inTopFrame())
|
||||
return;
|
||||
|
||||
const auto *FD = dyn_cast<FunctionDecl>(C.getLocationContext()->getDecl());
|
||||
const auto *FD = dyn_cast<FunctionDecl>(C.getStackFrame()->getDecl());
|
||||
if (!FD || FD->param_size() != 3 || !FD->isMain())
|
||||
return;
|
||||
|
||||
ProgramStateRef State = C.getState();
|
||||
const MemRegion *EnvpReg =
|
||||
State->getRegion(FD->parameters()[2], C.getLocationContext());
|
||||
State->getRegion(FD->parameters()[2], C.getStackFrame());
|
||||
|
||||
// Save the memory region pointed by the environment pointer parameter of
|
||||
// 'main'.
|
||||
|
|
|
|||
|
|
@ -107,10 +107,9 @@ using CallWithEntryStack = SmallVector<CallWithEntry, 6>;
|
|||
using VisitorsDiagnosticsTy =
|
||||
llvm::DenseMap<const ExplodedNode *, std::vector<PathDiagnosticPieceRef>>;
|
||||
|
||||
/// A map from PathDiagnosticPiece to the LocationContext of the inlined
|
||||
/// A map from PathDiagnosticPiece to the StackFrame of the inlined
|
||||
/// function call it represents.
|
||||
using LocationContextMap =
|
||||
llvm::DenseMap<const PathPieces *, const LocationContext *>;
|
||||
using StackFrameMap = llvm::DenseMap<const PathPieces *, const StackFrame *>;
|
||||
|
||||
/// A helper class that contains everything needed to construct a
|
||||
/// PathDiagnostic object. It does no much more then providing convenient
|
||||
|
|
@ -123,8 +122,8 @@ class PathDiagnosticConstruct {
|
|||
const ExplodedNode *CurrentNode;
|
||||
/// A mapping from parts of the bug path (for example, a function call, which
|
||||
/// would span backwards from a CallExit to a CallEnter with the nodes in
|
||||
/// between them) with the location contexts it is associated with.
|
||||
LocationContextMap LCM;
|
||||
/// between them) with the stack frames it is associated with.
|
||||
StackFrameMap SFM;
|
||||
const SourceManager &SM;
|
||||
|
||||
public:
|
||||
|
|
@ -143,18 +142,18 @@ public:
|
|||
const PathSensitiveBugReport *R,
|
||||
const Decl *AnalysisEntryPoint);
|
||||
|
||||
/// \returns the location context associated with the current position in the
|
||||
/// \returns the stack frame associated with the current position in the
|
||||
/// bug path.
|
||||
const LocationContext *getCurrLocationContext() const {
|
||||
const StackFrame *getCurrStackFrame() const {
|
||||
assert(CurrentNode && "Already reached the root!");
|
||||
return CurrentNode->getLocationContext();
|
||||
return CurrentNode->getStackFrame();
|
||||
}
|
||||
|
||||
/// Same as getCurrLocationContext (they should always return the same
|
||||
/// location context), but works after reaching the root of the bug path as
|
||||
/// Same as getCurrStackFrame (they should always return the same
|
||||
/// stack frame), but works after reaching the root of the bug path as
|
||||
/// well.
|
||||
const LocationContext *getLocationContextForActivePath() const {
|
||||
return LCM.find(&PD->getActivePath())->getSecond();
|
||||
const StackFrame *getStackFrameForActivePath() const {
|
||||
return SFM.find(&PD->getActivePath())->getSecond();
|
||||
}
|
||||
|
||||
const ExplodedNode *getCurrentNode() const { return CurrentNode; }
|
||||
|
|
@ -167,7 +166,7 @@ public:
|
|||
}
|
||||
|
||||
const ParentMap &getParentMap() const {
|
||||
return getCurrLocationContext()->getParentMap();
|
||||
return getCurrStackFrame()->getParentMap();
|
||||
}
|
||||
|
||||
const SourceManager &getSourceManager() const { return SM; }
|
||||
|
|
@ -176,18 +175,20 @@ public:
|
|||
return getParentMap().getParent(S);
|
||||
}
|
||||
|
||||
void updateLocCtxMap(const PathPieces *Path, const LocationContext *LC) {
|
||||
assert(Path && LC);
|
||||
LCM[Path] = LC;
|
||||
void updateStackFrameMap(const PathPieces *Path, const StackFrame *SF) {
|
||||
assert(Path && SF);
|
||||
SFM[Path] = SF;
|
||||
}
|
||||
|
||||
const LocationContext *getLocationContextFor(const PathPieces *Path) const {
|
||||
assert(LCM.count(Path) &&
|
||||
"Failed to find the context associated with these pieces!");
|
||||
return LCM.find(Path)->getSecond();
|
||||
const StackFrame *getStackFrameFor(const PathPieces *Path) const {
|
||||
assert(SFM.count(Path) &&
|
||||
"Failed to find the stack frame associated with these pieces!");
|
||||
return SFM.find(Path)->getSecond();
|
||||
}
|
||||
|
||||
bool isInLocCtxMap(const PathPieces *Path) const { return LCM.count(Path); }
|
||||
bool isInStackFrameMap(const PathPieces *Path) const {
|
||||
return SFM.count(Path);
|
||||
}
|
||||
|
||||
PathPieces &getActivePath() { return PD->getActivePath(); }
|
||||
PathPieces &getMutablePieces() { return PD->getMutablePieces(); }
|
||||
|
|
@ -323,7 +324,7 @@ std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){
|
|||
CallExitEnd CExit = P.castAs<CallExitEnd>();
|
||||
|
||||
// FIXME: Use CallEvent to abstract this over all calls.
|
||||
const Expr *CallSite = CExit.getCalleeContext()->getCallSite();
|
||||
const Expr *CallSite = CExit.getCalleeStackFrame()->getCallSite();
|
||||
const auto *CE = dyn_cast_or_null<CallExpr>(CallSite);
|
||||
if (!CE)
|
||||
return {};
|
||||
|
|
@ -467,10 +468,10 @@ static bool removeUnneededCalls(const PathDiagnosticConstruct &C,
|
|||
switch (piece->getKind()) {
|
||||
case PathDiagnosticPiece::Call: {
|
||||
auto &call = cast<PathDiagnosticCallPiece>(*piece);
|
||||
// Check if the location context is interesting.
|
||||
// Check if the stack frame is interesting.
|
||||
if (!removeUnneededCalls(
|
||||
C, call.path, R,
|
||||
R->isInteresting(C.getLocationContextFor(&call.path))))
|
||||
R->isInteresting(C.getStackFrameFor(&call.path))))
|
||||
continue;
|
||||
|
||||
containsSomethingInteresting = true;
|
||||
|
|
@ -610,10 +611,9 @@ static void removePiecesWithInvalidLocations(PathPieces &Pieces) {
|
|||
PathDiagnosticLocation PathDiagnosticBuilder::ExecutionContinues(
|
||||
const PathDiagnosticConstruct &C) const {
|
||||
if (const Stmt *S = C.getCurrentNode()->getNextStmtForDiagnostics())
|
||||
return PathDiagnosticLocation(S, getSourceManager(),
|
||||
C.getCurrLocationContext());
|
||||
return PathDiagnosticLocation(S, getSourceManager(), C.getCurrStackFrame());
|
||||
|
||||
return PathDiagnosticLocation::createDeclEnd(C.getCurrLocationContext(),
|
||||
return PathDiagnosticLocation::createDeclEnd(C.getCurrStackFrame(),
|
||||
getSourceManager());
|
||||
}
|
||||
|
||||
|
|
@ -631,7 +631,7 @@ PathDiagnosticLocation PathDiagnosticBuilder::ExecutionContinues(
|
|||
<< '.';
|
||||
else {
|
||||
os << "Execution jumps to the end of the ";
|
||||
const Decl *D = C.getCurrLocationContext()->getDecl();
|
||||
const Decl *D = C.getCurrStackFrame()->getDecl();
|
||||
if (isa<ObjCMethodDecl>(D))
|
||||
os << "method";
|
||||
else if (isa<FunctionDecl>(D))
|
||||
|
|
@ -669,61 +669,61 @@ static const Stmt *getEnclosingParent(const Stmt *S, const ParentMap &PM) {
|
|||
}
|
||||
|
||||
static PathDiagnosticLocation
|
||||
getEnclosingStmtLocation(const Stmt *S, const LocationContext *LC,
|
||||
getEnclosingStmtLocation(const Stmt *S, const StackFrame *SF,
|
||||
bool allowNestedContexts = false) {
|
||||
if (!S)
|
||||
return {};
|
||||
|
||||
const SourceManager &SMgr = LC->getDecl()->getASTContext().getSourceManager();
|
||||
const SourceManager &SMgr = SF->getDecl()->getASTContext().getSourceManager();
|
||||
|
||||
while (const Stmt *Parent = getEnclosingParent(S, LC->getParentMap())) {
|
||||
while (const Stmt *Parent = getEnclosingParent(S, SF->getParentMap())) {
|
||||
switch (Parent->getStmtClass()) {
|
||||
case Stmt::BinaryOperatorClass: {
|
||||
const auto *B = cast<BinaryOperator>(Parent);
|
||||
if (B->isLogicalOp())
|
||||
return PathDiagnosticLocation(allowNestedContexts ? B : S, SMgr, LC);
|
||||
return PathDiagnosticLocation(allowNestedContexts ? B : S, SMgr, SF);
|
||||
break;
|
||||
}
|
||||
case Stmt::CompoundStmtClass:
|
||||
case Stmt::StmtExprClass:
|
||||
return PathDiagnosticLocation(S, SMgr, LC);
|
||||
return PathDiagnosticLocation(S, SMgr, SF);
|
||||
case Stmt::ChooseExprClass:
|
||||
// Similar to '?' if we are referring to condition, just have the edge
|
||||
// point to the entire choose expression.
|
||||
if (allowNestedContexts || cast<ChooseExpr>(Parent)->getCond() == S)
|
||||
return PathDiagnosticLocation(Parent, SMgr, LC);
|
||||
return PathDiagnosticLocation(Parent, SMgr, SF);
|
||||
else
|
||||
return PathDiagnosticLocation(S, SMgr, LC);
|
||||
return PathDiagnosticLocation(S, SMgr, SF);
|
||||
case Stmt::BinaryConditionalOperatorClass:
|
||||
case Stmt::ConditionalOperatorClass:
|
||||
// For '?', if we are referring to condition, just have the edge point
|
||||
// to the entire '?' expression.
|
||||
if (allowNestedContexts ||
|
||||
cast<AbstractConditionalOperator>(Parent)->getCond() == S)
|
||||
return PathDiagnosticLocation(Parent, SMgr, LC);
|
||||
return PathDiagnosticLocation(Parent, SMgr, SF);
|
||||
else
|
||||
return PathDiagnosticLocation(S, SMgr, LC);
|
||||
return PathDiagnosticLocation(S, SMgr, SF);
|
||||
case Stmt::CXXForRangeStmtClass:
|
||||
if (cast<CXXForRangeStmt>(Parent)->getBody() == S)
|
||||
return PathDiagnosticLocation(S, SMgr, LC);
|
||||
return PathDiagnosticLocation(S, SMgr, SF);
|
||||
break;
|
||||
case Stmt::DoStmtClass:
|
||||
return PathDiagnosticLocation(S, SMgr, LC);
|
||||
return PathDiagnosticLocation(S, SMgr, SF);
|
||||
case Stmt::ForStmtClass:
|
||||
if (cast<ForStmt>(Parent)->getBody() == S)
|
||||
return PathDiagnosticLocation(S, SMgr, LC);
|
||||
return PathDiagnosticLocation(S, SMgr, SF);
|
||||
break;
|
||||
case Stmt::IfStmtClass:
|
||||
if (cast<IfStmt>(Parent)->getCond() != S)
|
||||
return PathDiagnosticLocation(S, SMgr, LC);
|
||||
return PathDiagnosticLocation(S, SMgr, SF);
|
||||
break;
|
||||
case Stmt::ObjCForCollectionStmtClass:
|
||||
if (cast<ObjCForCollectionStmt>(Parent)->getBody() == S)
|
||||
return PathDiagnosticLocation(S, SMgr, LC);
|
||||
return PathDiagnosticLocation(S, SMgr, SF);
|
||||
break;
|
||||
case Stmt::WhileStmtClass:
|
||||
if (cast<WhileStmt>(Parent)->getCond() != S)
|
||||
return PathDiagnosticLocation(S, SMgr, LC);
|
||||
return PathDiagnosticLocation(S, SMgr, SF);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
@ -734,7 +734,7 @@ getEnclosingStmtLocation(const Stmt *S, const LocationContext *LC,
|
|||
|
||||
assert(S && "Cannot have null Stmt for PathDiagnosticLocation");
|
||||
|
||||
return PathDiagnosticLocation(S, SMgr, LC);
|
||||
return PathDiagnosticLocation(S, SMgr, SF);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
@ -781,7 +781,7 @@ PathDiagnosticPieceRef PathDiagnosticBuilder::generateDiagForSwitchOP(
|
|||
PathDiagnosticLocation End;
|
||||
|
||||
if (const Stmt *S = Dst->getLabel()) {
|
||||
End = PathDiagnosticLocation(S, SM, C.getCurrLocationContext());
|
||||
End = PathDiagnosticLocation(S, SM, C.getCurrStackFrame());
|
||||
|
||||
switch (S->getStmtClass()) {
|
||||
default:
|
||||
|
|
@ -833,7 +833,7 @@ PathDiagnosticPieceRef PathDiagnosticBuilder::generateDiagForGotoOP(
|
|||
std::string sbuf;
|
||||
llvm::raw_string_ostream os(sbuf);
|
||||
const PathDiagnosticLocation &End =
|
||||
getEnclosingStmtLocation(S, C.getCurrLocationContext());
|
||||
getEnclosingStmtLocation(S, C.getCurrStackFrame());
|
||||
os << "Control jumps to line " << End.asLocation().getExpansionLineNumber();
|
||||
return std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, sbuf);
|
||||
}
|
||||
|
|
@ -856,13 +856,12 @@ PathDiagnosticPieceRef PathDiagnosticBuilder::generateDiagForBinaryOP(
|
|||
|
||||
if (*(Src->succ_begin() + 1) == Dst) {
|
||||
os << "false";
|
||||
End = PathDiagnosticLocation(B->getLHS(), SM, C.getCurrLocationContext());
|
||||
End = PathDiagnosticLocation(B->getLHS(), SM, C.getCurrStackFrame());
|
||||
Start =
|
||||
PathDiagnosticLocation::createOperatorLoc(B, SM);
|
||||
} else {
|
||||
os << "true";
|
||||
Start =
|
||||
PathDiagnosticLocation(B->getLHS(), SM, C.getCurrLocationContext());
|
||||
Start = PathDiagnosticLocation(B->getLHS(), SM, C.getCurrStackFrame());
|
||||
End = ExecutionContinues(C);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -872,12 +871,11 @@ PathDiagnosticPieceRef PathDiagnosticBuilder::generateDiagForBinaryOP(
|
|||
|
||||
if (*(Src->succ_begin() + 1) == Dst) {
|
||||
os << "false";
|
||||
Start =
|
||||
PathDiagnosticLocation(B->getLHS(), SM, C.getCurrLocationContext());
|
||||
Start = PathDiagnosticLocation(B->getLHS(), SM, C.getCurrStackFrame());
|
||||
End = ExecutionContinues(C);
|
||||
} else {
|
||||
os << "true";
|
||||
End = PathDiagnosticLocation(B->getLHS(), SM, C.getCurrLocationContext());
|
||||
End = PathDiagnosticLocation(B->getLHS(), SM, C.getCurrStackFrame());
|
||||
Start =
|
||||
PathDiagnosticLocation::createOperatorLoc(B, SM);
|
||||
}
|
||||
|
|
@ -888,14 +886,14 @@ PathDiagnosticPieceRef PathDiagnosticBuilder::generateDiagForBinaryOP(
|
|||
void PathDiagnosticBuilder::generateMinimalDiagForBlockEdge(
|
||||
PathDiagnosticConstruct &C, BlockEdge BE) const {
|
||||
const SourceManager &SM = getSourceManager();
|
||||
const LocationContext *LC = C.getCurrLocationContext();
|
||||
const StackFrame *SF = C.getCurrStackFrame();
|
||||
const CFGBlock *Src = BE.getSrc();
|
||||
const CFGBlock *Dst = BE.getDst();
|
||||
const Stmt *T = Src->getTerminatorStmt();
|
||||
if (!T)
|
||||
return;
|
||||
|
||||
auto Start = PathDiagnosticLocation::createBegin(T, SM, LC);
|
||||
auto Start = PathDiagnosticLocation::createBegin(T, SM, SF);
|
||||
switch (T->getStmtClass()) {
|
||||
default:
|
||||
break;
|
||||
|
|
@ -937,7 +935,7 @@ void PathDiagnosticBuilder::generateMinimalDiagForBlockEdge(
|
|||
PathDiagnosticLocation End = ExecutionContinues(C);
|
||||
|
||||
if (const Stmt *S = End.asStmt())
|
||||
End = getEnclosingStmtLocation(S, C.getCurrLocationContext());
|
||||
End = getEnclosingStmtLocation(S, C.getCurrStackFrame());
|
||||
|
||||
C.getActivePath().push_front(
|
||||
std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, sbuf));
|
||||
|
|
@ -962,7 +960,7 @@ void PathDiagnosticBuilder::generateMinimalDiagForBlockEdge(
|
|||
PathDiagnosticLocation End = ExecutionContinues(os, C);
|
||||
|
||||
if (const Stmt *S = End.asStmt())
|
||||
End = getEnclosingStmtLocation(S, C.getCurrLocationContext());
|
||||
End = getEnclosingStmtLocation(S, C.getCurrStackFrame());
|
||||
|
||||
C.getActivePath().push_front(
|
||||
std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, sbuf));
|
||||
|
|
@ -970,7 +968,7 @@ void PathDiagnosticBuilder::generateMinimalDiagForBlockEdge(
|
|||
PathDiagnosticLocation End = ExecutionContinues(C);
|
||||
|
||||
if (const Stmt *S = End.asStmt())
|
||||
End = getEnclosingStmtLocation(S, C.getCurrLocationContext());
|
||||
End = getEnclosingStmtLocation(S, C.getCurrStackFrame());
|
||||
|
||||
C.getActivePath().push_front(
|
||||
std::make_shared<PathDiagnosticControlFlowPiece>(
|
||||
|
|
@ -987,14 +985,14 @@ void PathDiagnosticBuilder::generateMinimalDiagForBlockEdge(
|
|||
os << "Loop condition is false. ";
|
||||
PathDiagnosticLocation End = ExecutionContinues(os, C);
|
||||
if (const Stmt *S = End.asStmt())
|
||||
End = getEnclosingStmtLocation(S, C.getCurrLocationContext());
|
||||
End = getEnclosingStmtLocation(S, C.getCurrStackFrame());
|
||||
|
||||
C.getActivePath().push_front(
|
||||
std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, sbuf));
|
||||
} else {
|
||||
PathDiagnosticLocation End = ExecutionContinues(C);
|
||||
if (const Stmt *S = End.asStmt())
|
||||
End = getEnclosingStmtLocation(S, C.getCurrLocationContext());
|
||||
End = getEnclosingStmtLocation(S, C.getCurrStackFrame());
|
||||
|
||||
C.getActivePath().push_front(
|
||||
std::make_shared<PathDiagnosticControlFlowPiece>(
|
||||
|
|
@ -1007,7 +1005,7 @@ void PathDiagnosticBuilder::generateMinimalDiagForBlockEdge(
|
|||
PathDiagnosticLocation End = ExecutionContinues(C);
|
||||
|
||||
if (const Stmt *S = End.asStmt())
|
||||
End = getEnclosingStmtLocation(S, C.getCurrLocationContext());
|
||||
End = getEnclosingStmtLocation(S, C.getCurrStackFrame());
|
||||
|
||||
if (*(Src->succ_begin() + 1) == Dst)
|
||||
C.getActivePath().push_front(
|
||||
|
|
@ -1161,8 +1159,8 @@ void PathDiagnosticBuilder::generatePathDiagnosticsForNode(
|
|||
|
||||
if (C.shouldAddPathEdges()) {
|
||||
// Add an edge to the start of the function.
|
||||
const StackFrame *CalleeLC = CE->getCalleeContext();
|
||||
const Decl *D = CalleeLC->getDecl();
|
||||
const StackFrame *CalleeSF = CE->getCalleeStackFrame();
|
||||
const Decl *D = CalleeSF->getDecl();
|
||||
// Add the edge only when the callee has body. We jump to the beginning
|
||||
// of the *declaration*, however we expect it to be followed by the
|
||||
// body. This isn't the case for autosynthesized property accessors in
|
||||
|
|
@ -1182,26 +1180,26 @@ void PathDiagnosticBuilder::generatePathDiagnosticsForNode(
|
|||
if (VisitedEntireCall) {
|
||||
Call = cast<PathDiagnosticCallPiece>(C.getActivePath().front().get());
|
||||
} else {
|
||||
// The path terminated within a nested location context, create a new
|
||||
// The path terminated within a nested stack frame, create a new
|
||||
// call piece to encapsulate the rest of the path pieces.
|
||||
const Decl *Caller = CE->getLocationContext()->getDecl();
|
||||
const Decl *Caller = CE->getStackFrame()->getDecl();
|
||||
Call = PathDiagnosticCallPiece::construct(C.getActivePath(), Caller);
|
||||
assert(C.getActivePath().size() == 1 &&
|
||||
C.getActivePath().front().get() == Call);
|
||||
|
||||
// Since we just transferred the path over to the call piece, reset the
|
||||
// mapping of the active path to the current location context.
|
||||
assert(C.isInLocCtxMap(&C.getActivePath()) &&
|
||||
// mapping of the active path to the current stack frame.
|
||||
assert(C.isInStackFrameMap(&C.getActivePath()) &&
|
||||
"When we ascend to a previously unvisited call, the active path's "
|
||||
"address shouldn't change, but rather should be compacted into "
|
||||
"a single CallEvent!");
|
||||
C.updateLocCtxMap(&C.getActivePath(), C.getCurrLocationContext());
|
||||
C.updateStackFrameMap(&C.getActivePath(), C.getCurrStackFrame());
|
||||
|
||||
// Record the location context mapping for the path within the call.
|
||||
assert(!C.isInLocCtxMap(&Call->path) &&
|
||||
// Record the stack frame mapping for the path within the call.
|
||||
assert(!C.isInStackFrameMap(&Call->path) &&
|
||||
"When we ascend to a previously unvisited call, this must be the "
|
||||
"first time we encounter the caller context!");
|
||||
C.updateLocCtxMap(&Call->path, CE->getCalleeContext());
|
||||
"first time we encounter the caller stack frame!");
|
||||
C.updateStackFrameMap(&Call->path, CE->getCalleeStackFrame());
|
||||
}
|
||||
Call->setCallee(*CE, SM);
|
||||
|
||||
|
|
@ -1215,9 +1213,9 @@ void PathDiagnosticBuilder::generatePathDiagnosticsForNode(
|
|||
return;
|
||||
}
|
||||
|
||||
assert(C.getCurrLocationContext() == C.getLocationContextForActivePath() &&
|
||||
assert(C.getCurrStackFrame() == C.getStackFrameForActivePath() &&
|
||||
"The current position in the bug path is out of sync with the "
|
||||
"location context associated with the active path!");
|
||||
"stack frame associated with the active path!");
|
||||
|
||||
// Have we encountered an exit from a function call?
|
||||
if (std::optional<CallExitEnd> CE = P.getAs<CallExitEnd>()) {
|
||||
|
|
@ -1225,11 +1223,11 @@ void PathDiagnosticBuilder::generatePathDiagnosticsForNode(
|
|||
// We are descending into a call (backwards). Construct
|
||||
// a new call piece to contain the path pieces for that call.
|
||||
auto Call = PathDiagnosticCallPiece::construct(*CE, SM);
|
||||
// Record the mapping from call piece to LocationContext.
|
||||
assert(!C.isInLocCtxMap(&Call->path) &&
|
||||
// Record the mapping from call piece to StackFrame.
|
||||
assert(!C.isInStackFrameMap(&Call->path) &&
|
||||
"We just entered a call, this must've been the first time we "
|
||||
"encounter its context!");
|
||||
C.updateLocCtxMap(&Call->path, CE->getCalleeContext());
|
||||
"encounter its stack frame!");
|
||||
C.updateStackFrameMap(&Call->path, CE->getCalleeStackFrame());
|
||||
|
||||
if (C.shouldAddPathEdges()) {
|
||||
// Add the edge to the return site.
|
||||
|
|
@ -1255,7 +1253,7 @@ void PathDiagnosticBuilder::generatePathDiagnosticsForNode(
|
|||
// as a terminator and as a terminator condition.
|
||||
if (!isa<ObjCForCollectionStmt>(PS->getStmt())) {
|
||||
PathDiagnosticLocation L =
|
||||
PathDiagnosticLocation(PS->getStmt(), SM, C.getCurrLocationContext());
|
||||
PathDiagnosticLocation(PS->getStmt(), SM, C.getCurrStackFrame());
|
||||
addEdgeToPath(C.getActivePath(), PrevLoc, L);
|
||||
}
|
||||
|
||||
|
|
@ -1271,7 +1269,7 @@ void PathDiagnosticBuilder::generatePathDiagnosticsForNode(
|
|||
|
||||
// Are we jumping to the head of a loop? Add a special diagnostic.
|
||||
if (const Stmt *Loop = BE->getSrc()->getLoopTarget()) {
|
||||
PathDiagnosticLocation L(Loop, SM, C.getCurrLocationContext());
|
||||
PathDiagnosticLocation L(Loop, SM, C.getCurrStackFrame());
|
||||
const Stmt *Body = nullptr;
|
||||
|
||||
if (const auto *FS = dyn_cast<ForStmt>(Loop))
|
||||
|
|
@ -1330,7 +1328,7 @@ void PathDiagnosticBuilder::generatePathDiagnosticsForNode(
|
|||
|
||||
if (!str.empty()) {
|
||||
PathDiagnosticLocation L(TermCond ? TermCond : Term, SM,
|
||||
C.getCurrLocationContext());
|
||||
C.getCurrStackFrame());
|
||||
auto PE = std::make_shared<PathDiagnosticEventPiece>(L, str);
|
||||
PE->setPrunable(true);
|
||||
addEdgeToPath(C.getActivePath(), PrevLoc, PE->getLocation());
|
||||
|
|
@ -1341,7 +1339,7 @@ void PathDiagnosticBuilder::generatePathDiagnosticsForNode(
|
|||
}
|
||||
}
|
||||
} else if (isa<BreakStmt, ContinueStmt, GotoStmt>(Term)) {
|
||||
PathDiagnosticLocation L(Term, SM, C.getCurrLocationContext());
|
||||
PathDiagnosticLocation L(Term, SM, C.getCurrStackFrame());
|
||||
addEdgeToPath(C.getActivePath(), PrevLoc, L);
|
||||
}
|
||||
}
|
||||
|
|
@ -1447,8 +1445,8 @@ using OptimizedCallsSet = llvm::DenseSet<const PathDiagnosticCallPiece *>;
|
|||
/// This avoids a "swoosh" effect, where an edge from a top-level statement A
|
||||
/// points to a sub-expression B.1 that's not at the start of B. In these cases,
|
||||
/// we'd like to see an edge from A to B, then another one from B to B.1.
|
||||
static void addContextEdges(PathPieces &pieces, const LocationContext *LC) {
|
||||
const ParentMap &PM = LC->getParentMap();
|
||||
static void addContextEdges(PathPieces &pieces, const StackFrame *SF) {
|
||||
const ParentMap &PM = SF->getParentMap();
|
||||
PathPieces::iterator Prev = pieces.end();
|
||||
for (PathPieces::iterator I = pieces.begin(), E = Prev; I != E;
|
||||
Prev = I, ++I) {
|
||||
|
|
@ -1465,7 +1463,7 @@ static void addContextEdges(PathPieces &pieces, const LocationContext *LC) {
|
|||
while (NextSrcContext.isValid() && NextSrcContext.asStmt() != InnerStmt) {
|
||||
SrcContexts.push_back(NextSrcContext);
|
||||
InnerStmt = NextSrcContext.asStmt();
|
||||
NextSrcContext = getEnclosingStmtLocation(InnerStmt, LC,
|
||||
NextSrcContext = getEnclosingStmtLocation(InnerStmt, SF,
|
||||
/*allowNested=*/true);
|
||||
}
|
||||
|
||||
|
|
@ -1478,7 +1476,7 @@ static void addContextEdges(PathPieces &pieces, const LocationContext *LC) {
|
|||
// We are looking at an edge. Is the destination within a larger
|
||||
// expression?
|
||||
PathDiagnosticLocation DstContext =
|
||||
getEnclosingStmtLocation(Dst, LC, /*allowNested=*/true);
|
||||
getEnclosingStmtLocation(Dst, SF, /*allowNested=*/true);
|
||||
if (!DstContext.isValid() || DstContext.asStmt() == Dst)
|
||||
break;
|
||||
|
||||
|
|
@ -1792,9 +1790,9 @@ static void removeIdenticalEvents(PathPieces &path) {
|
|||
static bool optimizeEdges(const PathDiagnosticConstruct &C, PathPieces &path,
|
||||
OptimizedCallsSet &OCS) {
|
||||
bool hasChanges = false;
|
||||
const LocationContext *LC = C.getLocationContextFor(&path);
|
||||
assert(LC);
|
||||
const ParentMap &PM = LC->getParentMap();
|
||||
const StackFrame *SF = C.getStackFrameFor(&path);
|
||||
assert(SF);
|
||||
const ParentMap &PM = SF->getParentMap();
|
||||
const SourceManager &SM = C.getSourceManager();
|
||||
|
||||
for (PathPieces::iterator I = path.begin(), E = path.end(); I != E; ) {
|
||||
|
|
@ -1950,7 +1948,7 @@ static bool optimizeEdges(const PathDiagnosticConstruct &C, PathPieces &path,
|
|||
if (!hasChanges) {
|
||||
// Adjust edges into subexpressions to make them more uniform
|
||||
// and aesthetically pleasing.
|
||||
addContextEdges(path, LC);
|
||||
addContextEdges(path, SF);
|
||||
// Remove "cyclical" edges that include one or more context edges.
|
||||
removeContextCycles(path, SM);
|
||||
// Hoist edges originating from branch conditions to branches
|
||||
|
|
@ -1978,7 +1976,7 @@ static void dropFunctionEntryEdge(const PathDiagnosticConstruct &C,
|
|||
if (!FirstEdge)
|
||||
return;
|
||||
|
||||
const Decl *D = C.getLocationContextFor(&Path)->getDecl();
|
||||
const Decl *D = C.getStackFrameFor(&Path)->getDecl();
|
||||
PathDiagnosticLocation EntryLoc =
|
||||
PathDiagnosticLocation::createBegin(D, C.getSourceManager());
|
||||
if (FirstEdge->getStartLocation() != EntryLoc)
|
||||
|
|
@ -2009,7 +2007,7 @@ PathDiagnosticConstruct::PathDiagnosticConstruct(
|
|||
SM(CurrentNode->getCodeDecl().getASTContext().getSourceManager()),
|
||||
PD(generateEmptyDiagnosticForReport(R, getSourceManager(),
|
||||
AnalysisEntryPoint)) {
|
||||
LCM[&PD->getActivePath()] = ErrorNode->getLocationContext();
|
||||
SFM[&PD->getActivePath()] = ErrorNode->getStackFrame();
|
||||
}
|
||||
|
||||
PathDiagnosticBuilder::PathDiagnosticBuilder(
|
||||
|
|
@ -2074,9 +2072,8 @@ PathDiagnosticBuilder::generate(const PathDiagnosticConsumer *PDC) const {
|
|||
if (PDC->shouldAddPathEdges()) {
|
||||
// Add an edge to the start of the function.
|
||||
// We'll prune it out later, but it helps make diagnostics more uniform.
|
||||
const StackFrame *CalleeLC =
|
||||
Construct.getLocationContextForActivePath()->getStackFrame();
|
||||
const Decl *D = CalleeLC->getDecl();
|
||||
const StackFrame *CalleeSF = Construct.getStackFrameForActivePath();
|
||||
const Decl *D = CalleeSF->getDecl();
|
||||
addEdgeToPath(Construct.getActivePath(), PrevLoc,
|
||||
PathDiagnosticLocation::createBegin(D, SM));
|
||||
}
|
||||
|
|
@ -2207,9 +2204,7 @@ const Decl *PathSensitiveBugReport::getDeclWithIssue() const {
|
|||
const ExplodedNode *N = getErrorNode();
|
||||
if (!N)
|
||||
return nullptr;
|
||||
|
||||
const LocationContext *LC = N->getLocationContext();
|
||||
return LC->getStackFrame()->getDecl();
|
||||
return N->getStackFrame()->getDecl();
|
||||
}
|
||||
|
||||
void BasicBugReport::Profile(llvm::FoldingSetNodeID& hash) const {
|
||||
|
|
@ -2333,10 +2328,10 @@ void PathSensitiveBugReport::markInteresting(SVal V,
|
|||
markInteresting(V.getAsSymbol(), TKind);
|
||||
}
|
||||
|
||||
void PathSensitiveBugReport::markInteresting(const LocationContext *LC) {
|
||||
if (!LC)
|
||||
void PathSensitiveBugReport::markInteresting(const StackFrame *SF) {
|
||||
if (!SF)
|
||||
return;
|
||||
InterestingLocationContexts.insert(LC);
|
||||
InterestingStackFrames.insert(SF);
|
||||
}
|
||||
|
||||
std::optional<bugreporter::TrackingKind>
|
||||
|
|
@ -2403,10 +2398,10 @@ bool PathSensitiveBugReport::isInteresting(const MemRegion *R) const {
|
|||
return getInterestingnessKind(R).has_value();
|
||||
}
|
||||
|
||||
bool PathSensitiveBugReport::isInteresting(const LocationContext *LC) const {
|
||||
if (!LC)
|
||||
bool PathSensitiveBugReport::isInteresting(const StackFrame *SF) const {
|
||||
if (!SF)
|
||||
return false;
|
||||
return InterestingLocationContexts.count(LC);
|
||||
return InterestingStackFrames.count(SF);
|
||||
}
|
||||
|
||||
const Stmt *PathSensitiveBugReport::getStmt() const {
|
||||
|
|
@ -2417,7 +2412,7 @@ const Stmt *PathSensitiveBugReport::getStmt() const {
|
|||
const Stmt *S = nullptr;
|
||||
|
||||
if (std::optional<BlockEntrance> BE = ProgP.getAs<BlockEntrance>()) {
|
||||
CFGBlock &Exit = ProgP.getLocationContext()->getCFG()->getExit();
|
||||
CFGBlock &Exit = ProgP.getStackFrame()->getCFG()->getExit();
|
||||
if (BE->getBlock() == &Exit)
|
||||
S = ErrorNode->getPreviousStmtForDiagnostics();
|
||||
}
|
||||
|
|
@ -2443,7 +2438,7 @@ static bool exitingDestructor(const ExplodedNode *N) {
|
|||
while (N && !N->getLocation().getAs<StmtPoint>()) {
|
||||
N = N->getFirstPred();
|
||||
}
|
||||
return N && isa<CXXDestructorDecl>(N->getLocationContext()->getDecl());
|
||||
return N && isa<CXXDestructorDecl>(N->getStackFrame()->getDecl());
|
||||
}
|
||||
|
||||
static const Stmt *
|
||||
|
|
@ -2464,23 +2459,25 @@ PathSensitiveBugReport::getLocation() const {
|
|||
assert(ErrorNode && "Cannot create a location with a null node.");
|
||||
const Stmt *S = ErrorNode->getStmtForDiagnostics();
|
||||
ProgramPoint P = ErrorNode->getLocation();
|
||||
const LocationContext *LC = P.getLocationContext();
|
||||
SourceManager &SM =
|
||||
ErrorNode->getState()->getStateManager().getContext().getSourceManager();
|
||||
const StackFrame *SF = P.getStackFrame();
|
||||
SourceManager &SM = ErrorNode->getState()
|
||||
->getStateManager()
|
||||
.getContext()
|
||||
.getSourceManager();
|
||||
|
||||
if (!S) {
|
||||
// If this is an implicit call, return the implicit call point location.
|
||||
if (!S) {
|
||||
// If this is an implicit call, return the implicit call point location.
|
||||
if (std::optional<PreImplicitCall> PIE = P.getAs<PreImplicitCall>())
|
||||
return PathDiagnosticLocation(PIE->getLocation(), SM);
|
||||
if (auto FE = P.getAs<FunctionExitPoint>()) {
|
||||
if (const ReturnStmt *RS = FE->getStmt())
|
||||
return PathDiagnosticLocation::createBegin(RS, SM, LC);
|
||||
return PathDiagnosticLocation::createBegin(RS, SM, SF);
|
||||
|
||||
S = findReasonableStmtCloseToFunctionExit(ErrorNode);
|
||||
}
|
||||
if (!S)
|
||||
S = ErrorNode->getNextStmtForDiagnostics();
|
||||
}
|
||||
}
|
||||
|
||||
if (S) {
|
||||
// Attributed statements usually have corrupted begin locations,
|
||||
|
|
@ -2498,17 +2495,16 @@ PathSensitiveBugReport::getLocation() const {
|
|||
return PathDiagnosticLocation::createOperatorLoc(B, SM);
|
||||
|
||||
if (P.getAs<PostStmtPurgeDeadSymbols>())
|
||||
return PathDiagnosticLocation::createEnd(S, SM, LC);
|
||||
return PathDiagnosticLocation::createEnd(S, SM, SF);
|
||||
|
||||
if (S->getBeginLoc().isValid())
|
||||
return PathDiagnosticLocation(S, SM, LC);
|
||||
return PathDiagnosticLocation(S, SM, SF);
|
||||
|
||||
return PathDiagnosticLocation(
|
||||
PathDiagnosticLocation::getValidSourceLocation(S, LC), SM);
|
||||
PathDiagnosticLocation::getValidSourceLocation(S, SF), SM);
|
||||
}
|
||||
|
||||
return PathDiagnosticLocation::createDeclEnd(ErrorNode->getLocationContext(),
|
||||
SM);
|
||||
return PathDiagnosticLocation::createDeclEnd(ErrorNode->getStackFrame(), SM);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
@ -3009,7 +3005,7 @@ void PathSensitiveBugReporter::emitReport(std::unique_ptr<BugReport> R) {
|
|||
"Error node must either be a sink or have a tag");
|
||||
|
||||
const AnalysisDeclContext *DeclCtx =
|
||||
E->getLocationContext()->getAnalysisDeclContext();
|
||||
E->getStackFrame()->getAnalysisDeclContext();
|
||||
// The source of autosynthesized body can be handcrafted AST or a model
|
||||
// file. The locations from handcrafted ASTs have no valid source
|
||||
// locations and have to be discarded. Locations from model files should
|
||||
|
|
@ -3261,11 +3257,11 @@ findExecutedLines(const SourceManager &SM, const ExplodedNode *N) {
|
|||
while (N) {
|
||||
if (N->getFirstPred() == nullptr) {
|
||||
// First node: show signature of the entrance point.
|
||||
const Decl *D = N->getLocationContext()->getDecl();
|
||||
const Decl *D = N->getStackFrame()->getDecl();
|
||||
populateExecutedLinesWithFunctionSignature(D, SM, *ExecutedLines);
|
||||
} else if (auto CE = N->getLocationAs<CallEnter>()) {
|
||||
// Inlined function: show signature.
|
||||
const Decl* D = CE->getCalleeContext()->getDecl();
|
||||
const Decl *D = CE->getCalleeStackFrame()->getDecl();
|
||||
populateExecutedLinesWithFunctionSignature(D, SM, *ExecutedLines);
|
||||
} else if (const Stmt *S = N->getStmtForDiagnostics()) {
|
||||
populateExecutedLinesWithStmt(S, SM, *ExecutedLines);
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ getLocationRegionIfReference(const Expr *E, const ExplodedNode *N,
|
|||
return nullptr;
|
||||
|
||||
if (FD->getType()->isReferenceType()) {
|
||||
SVal StructSVal = N->getState()->getLValue(VD, N->getLocationContext());
|
||||
SVal StructSVal = N->getState()->getLValue(VD, N->getStackFrame());
|
||||
return N->getState()->getLValue(FD, StructSVal).getAsRegion();
|
||||
}
|
||||
return nullptr;
|
||||
|
|
@ -202,7 +202,7 @@ getLocationRegionIfReference(const Expr *E, const ExplodedNode *N,
|
|||
return nullptr;
|
||||
if (LookingForReference && !VD->getType()->isReferenceType())
|
||||
return nullptr;
|
||||
return N->getState()->getLValue(VD, N->getLocationContext()).getAsRegion();
|
||||
return N->getState()->getLValue(VD, N->getStackFrame()).getAsRegion();
|
||||
}
|
||||
|
||||
/// Comparing internal representations of symbolic values (via
|
||||
|
|
@ -234,7 +234,7 @@ static bool hasVisibleUpdate(const ExplodedNode *LeftNode, SVal LeftVal,
|
|||
static std::optional<SVal> getSValForVar(const Expr *CondVarExpr,
|
||||
const ExplodedNode *N) {
|
||||
ProgramStateRef State = N->getState();
|
||||
const LocationContext *LCtx = N->getLocationContext();
|
||||
const StackFrame *SF = N->getStackFrame();
|
||||
|
||||
assert(CondVarExpr);
|
||||
CondVarExpr = CondVarExpr->IgnoreImpCasts();
|
||||
|
|
@ -245,11 +245,11 @@ static std::optional<SVal> getSValForVar(const Expr *CondVarExpr,
|
|||
// capture variable. We most likely need to duplicate that logic here.
|
||||
if (const auto *DRE = dyn_cast<DeclRefExpr>(CondVarExpr))
|
||||
if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl()))
|
||||
return State->getSVal(State->getLValue(VD, LCtx));
|
||||
return State->getSVal(State->getLValue(VD, SF));
|
||||
|
||||
if (const auto *ME = dyn_cast<MemberExpr>(CondVarExpr))
|
||||
if (const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
|
||||
if (auto FieldL = State->getSVal(ME, LCtx).getAs<Loc>())
|
||||
if (auto FieldL = State->getSVal(ME, SF).getAs<Loc>())
|
||||
return State->getRawSVal(*FieldL, FD->getType());
|
||||
|
||||
return std::nullopt;
|
||||
|
|
@ -378,8 +378,7 @@ BugReporterVisitor::getDefaultEndPath(const BugReporterContext &BRC,
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
bool NoStateChangeFuncVisitor::isModifiedInFrame(const ExplodedNode *N) {
|
||||
const LocationContext *Ctx = N->getLocationContext();
|
||||
const StackFrame *SF = Ctx->getStackFrame();
|
||||
const StackFrame *SF = N->getStackFrame();
|
||||
if (!FramesModifyingCalculated.count(SF))
|
||||
findModifyingFrames(N);
|
||||
return FramesModifying.count(SF);
|
||||
|
|
@ -391,7 +390,7 @@ void NoStateChangeFuncVisitor::markFrameAsModifying(const StackFrame *SF) {
|
|||
if (!p.second)
|
||||
break; // Frame and all its parents already inserted.
|
||||
|
||||
SF = SF->getParent()->getStackFrame();
|
||||
SF = SF->getParent();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -420,8 +419,7 @@ void NoStateChangeFuncVisitor::findModifyingFrames(
|
|||
|
||||
assert(CallExitBeginN->getLocationAs<CallExitBegin>());
|
||||
|
||||
const StackFrame *const OriginalSF =
|
||||
CallExitBeginN->getLocationContext()->getStackFrame();
|
||||
const StackFrame *const OriginalSF = CallExitBeginN->getStackFrame();
|
||||
|
||||
const ExplodedNode *CurrCallExitBeginN = CallExitBeginN;
|
||||
const StackFrame *CurrentSF = OriginalSF;
|
||||
|
|
@ -451,7 +449,7 @@ void NoStateChangeFuncVisitor::findModifyingFrames(
|
|||
// F.field = 0; // note: 0 assigned to 'F.field'
|
||||
// // note: returning without writing to 'F.field'
|
||||
// }
|
||||
if (CE->getCalleeContext() == OriginalSF) {
|
||||
if (CE->getCalleeStackFrame() == OriginalSF) {
|
||||
markFrameAsModifying(CurrentSF);
|
||||
break;
|
||||
}
|
||||
|
|
@ -465,8 +463,7 @@ void NoStateChangeFuncVisitor::findModifyingFrames(
|
|||
PathDiagnosticPieceRef NoStateChangeFuncVisitor::VisitNode(
|
||||
const ExplodedNode *N, BugReporterContext &BR, PathSensitiveBugReport &R) {
|
||||
|
||||
const LocationContext *Ctx = N->getLocationContext();
|
||||
const StackFrame *SF = Ctx->getStackFrame();
|
||||
const StackFrame *SF = N->getStackFrame();
|
||||
ProgramStateRef State = N->getState();
|
||||
auto CallExitLoc = N->getLocationAs<CallExitBegin>();
|
||||
|
||||
|
|
@ -867,7 +864,6 @@ private:
|
|||
std::optional<SourceLocation> matchAssignment(const ExplodedNode *N) {
|
||||
const Stmt *S = N->getStmtForDiagnostics();
|
||||
ProgramStateRef State = N->getState();
|
||||
auto *LCtx = N->getLocationContext();
|
||||
if (!S)
|
||||
return std::nullopt;
|
||||
|
||||
|
|
@ -875,7 +871,7 @@ private:
|
|||
if (const auto *VD = dyn_cast<VarDecl>(DS->getSingleDecl()))
|
||||
if (const Expr *RHS = VD->getInit())
|
||||
if (RegionOfInterest->isSubRegionOf(
|
||||
State->getLValue(VD, LCtx).getAsRegion()))
|
||||
State->getLValue(VD, N->getStackFrame()).getAsRegion()))
|
||||
return RHS->getBeginLoc();
|
||||
} else if (const auto *BO = dyn_cast<BinaryOperator>(S)) {
|
||||
const MemRegion *R = N->getSVal(BO->getLHS()).getAsRegion();
|
||||
|
|
@ -934,7 +930,7 @@ public:
|
|||
BugReporterContext &BRC,
|
||||
PathSensitiveBugReport &BR) {
|
||||
// Only print a message at the interesting return statement.
|
||||
if (N->getLocationContext() != CalleeSF)
|
||||
if (N->getStackFrame() != CalleeSF)
|
||||
return nullptr;
|
||||
|
||||
std::optional<StmtPoint> SP = N->getLocationAs<StmtPoint>();
|
||||
|
|
@ -1065,7 +1061,7 @@ public:
|
|||
if (!CE)
|
||||
return nullptr;
|
||||
|
||||
if (CE->getCalleeContext() != CalleeSF)
|
||||
if (CE->getCalleeStackFrame() != CalleeSF)
|
||||
return nullptr;
|
||||
|
||||
Mode = Satisfied;
|
||||
|
|
@ -1205,8 +1201,7 @@ static bool isInitializationOfVar(const ExplodedNode *N, const VarRegion *VR) {
|
|||
}
|
||||
|
||||
assert(VR->getDecl()->hasLocalStorage());
|
||||
const LocationContext *LCtx = N->getLocationContext();
|
||||
return FrameSpace->getStackFrame() == LCtx->getStackFrame();
|
||||
return FrameSpace->getStackFrame() == N->getStackFrame();
|
||||
}
|
||||
|
||||
static bool isObjCPointer(const MemRegion *R) {
|
||||
|
|
@ -1568,7 +1563,7 @@ PathDiagnosticPieceRef StoreSiteFinder::VisitNode(const ExplodedNode *Succ,
|
|||
// Get the region for the object we copied/moved from.
|
||||
const auto *OriginEx = CE->getArg(0);
|
||||
const auto OriginVal =
|
||||
State->getSVal(OriginEx, Succ->getLocationContext());
|
||||
State->getSVal(OriginEx, Succ->getStackFrame());
|
||||
|
||||
// Pop the stored field regions and apply them to the origin
|
||||
// object in the same order we had them on the copy.
|
||||
|
|
@ -1616,14 +1611,16 @@ PathDiagnosticPieceRef StoreSiteFinder::VisitNode(const ExplodedNode *Succ,
|
|||
ProgramStateManager &StateMgr = BRC.getStateManager();
|
||||
CallEventManager &CallMgr = StateMgr.getCallEventManager();
|
||||
|
||||
CallEventRef<> Call = CallMgr.getCaller(CE->getCalleeContext(),
|
||||
Succ->getState());
|
||||
CallEventRef<> Call =
|
||||
CallMgr.getCaller(CE->getCalleeStackFrame(), Succ->getState());
|
||||
InitE = Call->getArgExpr(Param->getFunctionScopeIndex());
|
||||
} else {
|
||||
// Handle Objective-C 'self'.
|
||||
assert(isa<ImplicitParamDecl>(VR->getDecl()));
|
||||
InitE = cast<ObjCMessageExpr>(CE->getCalleeContext()->getCallSite())
|
||||
->getInstanceReceiver()->IgnoreParenCasts();
|
||||
InitE =
|
||||
cast<ObjCMessageExpr>(CE->getCalleeStackFrame()->getCallSite())
|
||||
->getInstanceReceiver()
|
||||
->IgnoreParenCasts();
|
||||
}
|
||||
IsParam = true;
|
||||
}
|
||||
|
|
@ -1883,10 +1880,10 @@ SuppressInlineDefensiveChecksVisitor::VisitNode(const ExplodedNode *Succ,
|
|||
IsSatisfied = true;
|
||||
|
||||
// Check if this is inlined defensive checks.
|
||||
const LocationContext *CurLC = Succ->getLocationContext();
|
||||
const LocationContext *ReportLC = BR.getErrorNode()->getLocationContext();
|
||||
if (CurLC != ReportLC && !CurLC->isParentOf(ReportLC)) {
|
||||
BR.markInvalid("Suppress IDC", CurLC);
|
||||
const StackFrame *CurSF = Succ->getStackFrame();
|
||||
const StackFrame *ReportSF = BR.getErrorNode()->getStackFrame();
|
||||
if (CurSF != ReportSF && !CurSF->isParentOf(ReportSF)) {
|
||||
BR.markInvalid("Suppress IDC", CurSF);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -1908,7 +1905,7 @@ SuppressInlineDefensiveChecksVisitor::VisitNode(const ExplodedNode *Succ,
|
|||
if (!CurStmt->getBeginLoc().isMacroID())
|
||||
return nullptr;
|
||||
|
||||
const CFGStmtMap *Map = CurLC->getAnalysisDeclContext()->getCFGStmtMap();
|
||||
const CFGStmtMap *Map = CurSF->getAnalysisDeclContext()->getCFGStmtMap();
|
||||
CurTerminatorStmt = Map->getBlock(CurStmt)->getTerminatorStmt();
|
||||
} else {
|
||||
return nullptr;
|
||||
|
|
@ -1924,7 +1921,7 @@ SuppressInlineDefensiveChecksVisitor::VisitNode(const ExplodedNode *Succ,
|
|||
// Suppress reports unless we are in that same macro.
|
||||
if (!BugLoc.isMacroID() ||
|
||||
getMacroName(BugLoc, BRC) != getMacroName(TerminatorLoc, BRC)) {
|
||||
BR.markInvalid("Suppress Macro IDC", CurLC);
|
||||
BR.markInvalid("Suppress Macro IDC", CurSF);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
|
@ -1985,9 +1982,9 @@ constructDebugPieceForTrackedCondition(const Expr *Cond,
|
|||
BRC.getSourceManager(), BRC.getASTContext().getLangOpts()));
|
||||
|
||||
return std::make_shared<PathDiagnosticEventPiece>(
|
||||
PathDiagnosticLocation::createBegin(
|
||||
Cond, BRC.getSourceManager(), N->getLocationContext()),
|
||||
(Twine() + "Tracking condition '" + ConditionText + "'").str());
|
||||
PathDiagnosticLocation::createBegin(Cond, BRC.getSourceManager(),
|
||||
N->getStackFrame()),
|
||||
(Twine() + "Tracking condition '" + ConditionText + "'").str());
|
||||
}
|
||||
|
||||
static bool isAssertlikeBlock(const CFGBlock *B, ASTContext &Context) {
|
||||
|
|
@ -2181,7 +2178,7 @@ PathDiagnosticPieceRef StoreHandler::constructNote(StoreInfo SI,
|
|||
PathDiagnosticLocation L;
|
||||
if (P.getAs<CallEnter>() && SI.SourceOfTheValue)
|
||||
L = PathDiagnosticLocation(SI.SourceOfTheValue, BRC.getSourceManager(),
|
||||
P.getLocationContext());
|
||||
P.getStackFrame());
|
||||
|
||||
if (!L.isValid() || !L.asLocation().isValid())
|
||||
L = PathDiagnosticLocation::create(P, BRC.getSourceManager());
|
||||
|
|
@ -2386,14 +2383,14 @@ class InlinedFunctionCallHandler final : public ExpressionHandler {
|
|||
// as a 'StmtPoint' so we have to bypass it.
|
||||
const bool BypassCXXNewExprEval = isa<CXXNewExpr>(E);
|
||||
|
||||
// This is moving forward when we enter into another context.
|
||||
// This is moving forward when we enter into another stack frame.
|
||||
const StackFrame *CurrentSF = ExprNode->getStackFrame();
|
||||
|
||||
do {
|
||||
// If that is satisfied we found our statement as an inlined call.
|
||||
if (std::optional<CallExitEnd> CEE =
|
||||
ExprNode->getLocationAs<CallExitEnd>())
|
||||
if (CEE->getCalleeContext()->getCallSite() == E)
|
||||
if (CEE->getCalleeStackFrame()->getCallSite() == E)
|
||||
break;
|
||||
|
||||
// Try to move forward to the end of the call-chain.
|
||||
|
|
@ -2408,7 +2405,7 @@ class InlinedFunctionCallHandler final : public ExpressionHandler {
|
|||
// conservatively evaluated allocator.
|
||||
if (!BypassCXXNewExprEval)
|
||||
if (std::optional<StmtPoint> SP = ExprNode->getLocationAs<StmtPoint>())
|
||||
// See if we do not enter into another context.
|
||||
// See if we do not enter into another stack frame.
|
||||
if (SP->getStmt() == E && CurrentSF == PredSF)
|
||||
break;
|
||||
|
||||
|
|
@ -2426,8 +2423,8 @@ class InlinedFunctionCallHandler final : public ExpressionHandler {
|
|||
if (!CEE)
|
||||
return {};
|
||||
|
||||
const StackFrame *CalleeContext = CEE->getCalleeContext();
|
||||
if (CalleeContext->getCallSite() != E)
|
||||
const StackFrame *CalleeSF = CEE->getCalleeStackFrame();
|
||||
if (CalleeSF->getCallSite() != E)
|
||||
return {};
|
||||
|
||||
// Check the return value.
|
||||
|
|
@ -2448,7 +2445,7 @@ class InlinedFunctionCallHandler final : public ExpressionHandler {
|
|||
EnableNullFPSuppression = State->isNull(*RetLoc).isConstrainedTrue();
|
||||
|
||||
PathSensitiveBugReport &Report = getParentTracker().getReport();
|
||||
Report.addVisitor<ReturnVisitor>(&getParentTracker(), CalleeContext,
|
||||
Report.addVisitor<ReturnVisitor>(&getParentTracker(), CalleeSF,
|
||||
EnableNullFPSuppression, Options,
|
||||
Opts.Kind);
|
||||
return {true};
|
||||
|
|
@ -2469,7 +2466,7 @@ public:
|
|||
|
||||
// If the expression is not an "lvalue expression", we can still
|
||||
// track the constraints on its contents.
|
||||
SVal V = LVState->getSValAsScalarOrLoc(Inner, LVNode->getLocationContext());
|
||||
SVal V = LVState->getSValAsScalarOrLoc(Inner, LVNode->getStackFrame());
|
||||
|
||||
// Is it a symbolic value?
|
||||
if (auto L = V.getAs<loc::MemRegionVal>()) {
|
||||
|
|
@ -2556,14 +2553,14 @@ public:
|
|||
}
|
||||
|
||||
ProgramStateRef RVState = RVNode->getState();
|
||||
SVal V = RVState->getSValAsScalarOrLoc(E, RVNode->getLocationContext());
|
||||
SVal V = RVState->getSValAsScalarOrLoc(E, RVNode->getStackFrame());
|
||||
const auto *BO = dyn_cast<BinaryOperator>(E);
|
||||
|
||||
if (!BO || !BO->isMultiplicativeOp() || !V.isZeroConstant())
|
||||
return {};
|
||||
|
||||
SVal RHSV = RVState->getSVal(BO->getRHS(), RVNode->getLocationContext());
|
||||
SVal LHSV = RVState->getSVal(BO->getLHS(), RVNode->getLocationContext());
|
||||
SVal RHSV = RVState->getSVal(BO->getRHS(), RVNode->getStackFrame());
|
||||
SVal LHSV = RVState->getSVal(BO->getLHS(), RVNode->getStackFrame());
|
||||
|
||||
// Track both LHS and RHS of a multiplication.
|
||||
if (BO->getOpcode() == BO_Mul) {
|
||||
|
|
@ -2708,7 +2705,7 @@ NilReceiverBRVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
|
|||
/*EnableNullFPSuppression*/ false});
|
||||
// Issue a message saying that the method was skipped.
|
||||
PathDiagnosticLocation L(Receiver, BRC.getSourceManager(),
|
||||
N->getLocationContext());
|
||||
N->getStackFrame());
|
||||
return std::make_shared<PathDiagnosticEventPiece>(L, OS.str());
|
||||
}
|
||||
|
||||
|
|
@ -2840,7 +2837,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, BugReporterContext &BRC,
|
|||
const ExplodedNode *N, bool TookTrue) {
|
||||
ProgramStateRef CurrentState = N->getState();
|
||||
ProgramStateRef PrevState = N->getFirstPred()->getState();
|
||||
const LocationContext *LCtx = N->getLocationContext();
|
||||
const StackFrame *SF = N->getStackFrame();
|
||||
|
||||
// If the constraint information is changed between the current and the
|
||||
// previous program state we assuming the newly seen constraint information.
|
||||
|
|
@ -2858,7 +2855,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, BugReporterContext &BRC,
|
|||
// this is not a "real" assumption.
|
||||
bool IsAssuming =
|
||||
!BRC.getStateManager().haveEqualConstraints(CurrentState, PrevState) ||
|
||||
CurrentState->getSVal(Cond, LCtx).isUnknownOrUndef();
|
||||
CurrentState->getSVal(Cond, SF).isUnknownOrUndef();
|
||||
|
||||
// These will be modified in code below, but we need to preserve the original
|
||||
// values in case we want to throw the generic message.
|
||||
|
|
@ -2905,7 +2902,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, BugReporterContext &BRC,
|
|||
if (!IsAssuming)
|
||||
return nullptr;
|
||||
|
||||
PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LCtx);
|
||||
PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), SF);
|
||||
if (!Loc.isValid() || !Loc.asLocation().isValid())
|
||||
return nullptr;
|
||||
|
||||
|
|
@ -2944,10 +2941,10 @@ bool ConditionBRVisitor::patternMatch(const Expr *Ex, const Expr *ParentEx,
|
|||
const bool quotes = isa<VarDecl>(DR->getDecl());
|
||||
if (quotes) {
|
||||
Out << '\'';
|
||||
const LocationContext *LCtx = N->getLocationContext();
|
||||
const ProgramState *state = N->getState().get();
|
||||
if (const MemRegion *R = state->getLValue(cast<VarDecl>(DR->getDecl()),
|
||||
LCtx).getAsRegion()) {
|
||||
if (const MemRegion *R =
|
||||
state->getLValue(cast<VarDecl>(DR->getDecl()), N->getStackFrame())
|
||||
.getAsRegion()) {
|
||||
if (report.isInteresting(R))
|
||||
prunable = false;
|
||||
else {
|
||||
|
|
@ -3082,7 +3079,7 @@ PathDiagnosticPieceRef ConditionBRVisitor::VisitTrueTest(
|
|||
}
|
||||
|
||||
Out << (shouldInvert ? LhsString : RhsString);
|
||||
const LocationContext *LCtx = N->getLocationContext();
|
||||
const StackFrame *SF = N->getStackFrame();
|
||||
const SourceManager &SM = BRC.getSourceManager();
|
||||
|
||||
if (isVarAnInterestingCondition(BExpr->getLHS(), N, &R) ||
|
||||
|
|
@ -3100,18 +3097,18 @@ PathDiagnosticPieceRef ConditionBRVisitor::VisitTrueTest(
|
|||
if (LhsME && LhsME->getMemberLoc().isValid())
|
||||
Loc = PathDiagnosticLocation(LhsME->getMemberLoc(), SM);
|
||||
else
|
||||
Loc = PathDiagnosticLocation(BExpr->getLHS(), SM, LCtx);
|
||||
Loc = PathDiagnosticLocation(BExpr->getLHS(), SM, SF);
|
||||
} else {
|
||||
if (RhsME && RhsME->getMemberLoc().isValid())
|
||||
Loc = PathDiagnosticLocation(RhsME->getMemberLoc(), SM);
|
||||
else
|
||||
Loc = PathDiagnosticLocation(BExpr->getRHS(), SM, LCtx);
|
||||
Loc = PathDiagnosticLocation(BExpr->getRHS(), SM, SF);
|
||||
}
|
||||
|
||||
return std::make_shared<PathDiagnosticPopUpPiece>(Loc, Message);
|
||||
}
|
||||
|
||||
PathDiagnosticLocation Loc(Cond, SM, LCtx);
|
||||
PathDiagnosticLocation Loc(Cond, SM, SF);
|
||||
auto event = std::make_shared<PathDiagnosticEventPiece>(Loc, Message);
|
||||
if (shouldPrune)
|
||||
event->setPrunable(*shouldPrune);
|
||||
|
|
@ -3131,8 +3128,8 @@ PathDiagnosticPieceRef ConditionBRVisitor::VisitConditionVariable(
|
|||
if (!printValue(CondVarExpr, Out, N, TookTrue, /*IsAssuming=*/true))
|
||||
return nullptr;
|
||||
|
||||
const LocationContext *LCtx = N->getLocationContext();
|
||||
PathDiagnosticLocation Loc(CondVarExpr, BRC.getSourceManager(), LCtx);
|
||||
PathDiagnosticLocation Loc(CondVarExpr, BRC.getSourceManager(),
|
||||
N->getStackFrame());
|
||||
|
||||
if (isVarAnInterestingCondition(CondVarExpr, N, &report))
|
||||
Out << WillBeUsedForACondition;
|
||||
|
|
@ -3161,18 +3158,18 @@ PathDiagnosticPieceRef ConditionBRVisitor::VisitTrueTest(
|
|||
if (!printValue(DRE, Out, N, TookTrue, IsAssuming))
|
||||
return nullptr;
|
||||
|
||||
const LocationContext *LCtx = N->getLocationContext();
|
||||
const StackFrame *SF = N->getStackFrame();
|
||||
|
||||
if (isVarAnInterestingCondition(DRE, N, &report))
|
||||
Out << WillBeUsedForACondition;
|
||||
|
||||
// If we know the value create a pop-up note to the 'DRE'.
|
||||
if (!IsAssuming) {
|
||||
PathDiagnosticLocation Loc(DRE, BRC.getSourceManager(), LCtx);
|
||||
PathDiagnosticLocation Loc(DRE, BRC.getSourceManager(), SF);
|
||||
return std::make_shared<PathDiagnosticPopUpPiece>(Loc, Out.str());
|
||||
}
|
||||
|
||||
PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LCtx);
|
||||
PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), SF);
|
||||
auto event = std::make_shared<PathDiagnosticEventPiece>(Loc, Out.str());
|
||||
|
||||
if (isInterestingExpr(DRE, N, &report))
|
||||
|
|
@ -3194,14 +3191,14 @@ PathDiagnosticPieceRef ConditionBRVisitor::VisitTrueTest(
|
|||
if (!printValue(ME, Out, N, TookTrue, IsAssuming))
|
||||
return nullptr;
|
||||
|
||||
const LocationContext *LCtx = N->getLocationContext();
|
||||
PathDiagnosticLocation Loc;
|
||||
|
||||
// If we know the value create a pop-up note to the member of the MemberExpr.
|
||||
if (!IsAssuming && ME->getMemberLoc().isValid())
|
||||
Loc = PathDiagnosticLocation(ME->getMemberLoc(), BRC.getSourceManager());
|
||||
else
|
||||
Loc = PathDiagnosticLocation(Cond, BRC.getSourceManager(), LCtx);
|
||||
Loc = PathDiagnosticLocation(Cond, BRC.getSourceManager(),
|
||||
N->getStackFrame());
|
||||
|
||||
if (!Loc.isValid() || !Loc.asLocation().isValid())
|
||||
return nullptr;
|
||||
|
|
@ -3272,7 +3269,7 @@ void LikelyFalsePositiveSuppressionBRVisitor::finalizeVisitor(
|
|||
// Here we suppress false positives coming from system headers. This list is
|
||||
// based on known issues.
|
||||
const AnalyzerOptions &Options = BRC.getAnalyzerOptions();
|
||||
const Decl *D = N->getLocationContext()->getDecl();
|
||||
const Decl *D = N->getStackFrame()->getDecl();
|
||||
|
||||
if (AnalysisDeclContext::isInStdNamespace(D)) {
|
||||
// Skip reports within the 'std' namespace. Although these can sometimes be
|
||||
|
|
@ -3307,9 +3304,8 @@ void LikelyFalsePositiveSuppressionBRVisitor::finalizeVisitor(
|
|||
}
|
||||
}
|
||||
|
||||
for (const LocationContext *LCtx = N->getLocationContext(); LCtx;
|
||||
LCtx = LCtx->getParent()) {
|
||||
const auto *MD = dyn_cast<CXXMethodDecl>(LCtx->getDecl());
|
||||
for (const auto *SF = N->getStackFrame(); SF; SF = SF->getParent()) {
|
||||
const auto *MD = dyn_cast<CXXMethodDecl>(SF->getDecl());
|
||||
if (!MD)
|
||||
continue;
|
||||
|
||||
|
|
@ -3366,7 +3362,7 @@ UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
|
|||
|
||||
// Check if one of the arguments is the region the visitor is tracking.
|
||||
CallEventManager &CEMgr = BRC.getStateManager().getCallEventManager();
|
||||
CallEventRef<> Call = CEMgr.getCaller(CEnter->getCalleeContext(), State);
|
||||
CallEventRef<> Call = CEMgr.getCaller(CEnter->getCalleeStackFrame(), State);
|
||||
unsigned Idx = 0;
|
||||
ArrayRef<ParmVarDecl *> parms = Call->parameters();
|
||||
|
||||
|
|
@ -3392,11 +3388,11 @@ UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
|
|||
if (T->getPointeeType().isConstQualified())
|
||||
continue;
|
||||
|
||||
// Mark the call site (LocationContext) as interesting if the value of the
|
||||
// Mark the call site (StackFrame) as interesting if the value of the
|
||||
// argument is undefined or '0'/'NULL'.
|
||||
SVal BoundVal = State->getSVal(R);
|
||||
if (BoundVal.isUndef() || BoundVal.isZeroConstant()) {
|
||||
BR.markInteresting(CEnter->getCalleeContext());
|
||||
BR.markInteresting(CEnter->getCalleeStackFrame());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ AnalysisDeclContext *CallEvent::getCalleeAnalysisDeclContext() const {
|
|||
return nullptr;
|
||||
|
||||
AnalysisDeclContext *ADC =
|
||||
LCtx->getAnalysisDeclContext()->getManager()->getContext(D);
|
||||
SF->getAnalysisDeclContext()->getManager()->getContext(D);
|
||||
|
||||
return ADC;
|
||||
}
|
||||
|
|
@ -173,7 +173,7 @@ const StackFrame *CallEvent::getCalleeStackFrame(unsigned BlockCount) const {
|
|||
// instead of doing this reverse lookup, we would be able to build the stack
|
||||
// frame for non-expression-based calls, and also we wouldn't need the reverse
|
||||
// lookup.
|
||||
const CFGStmtMap *Map = LCtx->getAnalysisDeclContext()->getCFGStmtMap();
|
||||
const CFGStmtMap *Map = SF->getAnalysisDeclContext()->getCFGStmtMap();
|
||||
const CFGBlock *B = Map->getBlock(E);
|
||||
assert(B);
|
||||
|
||||
|
|
@ -185,7 +185,7 @@ const StackFrame *CallEvent::getCalleeStackFrame(unsigned BlockCount) const {
|
|||
break;
|
||||
assert(Idx < Sz);
|
||||
|
||||
return ADC->getStackFrame(LCtx, nullptr, E, B, BlockCount, Idx);
|
||||
return ADC->getStackFrame(SF, nullptr, E, B, BlockCount, Idx);
|
||||
}
|
||||
|
||||
const ParamVarRegion
|
||||
|
|
@ -296,7 +296,7 @@ ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount,
|
|||
// NOTE: Even if RegionsToInvalidate is empty, we may still invalidate
|
||||
// global variables.
|
||||
return State->invalidateRegions(ValuesToInvalidate, getCFGElementRef(),
|
||||
BlockCount, getLocationContext(),
|
||||
BlockCount, getStackFrame(),
|
||||
/*CausedByPointerEscape*/ true,
|
||||
/*Symbols=*/nullptr, this, &ETraits);
|
||||
}
|
||||
|
|
@ -306,8 +306,8 @@ ProgramPoint CallEvent::getProgramPoint(bool IsPreVisit,
|
|||
|
||||
if (const Expr *E = getOriginExpr()) {
|
||||
if (IsPreVisit)
|
||||
return PreStmt(E, getLocationContext(), Tag);
|
||||
return PostStmt(E, getLocationContext(), Tag);
|
||||
return PreStmt(E, getStackFrame(), Tag);
|
||||
return PostStmt(E, getStackFrame(), Tag);
|
||||
}
|
||||
|
||||
const Decl *D = getDecl();
|
||||
|
|
@ -317,8 +317,8 @@ ProgramPoint CallEvent::getProgramPoint(bool IsPreVisit,
|
|||
|
||||
SourceLocation Loc = getSourceRange().getBegin();
|
||||
if (IsPreVisit)
|
||||
return PreImplicitCall(D, Loc, getLocationContext(), ElemRef, Tag);
|
||||
return PostImplicitCall(D, Loc, getLocationContext(), ElemRef, Tag);
|
||||
return PreImplicitCall(D, Loc, getStackFrame(), ElemRef, Tag);
|
||||
return PostImplicitCall(D, Loc, getStackFrame(), ElemRef, Tag);
|
||||
}
|
||||
|
||||
SVal CallEvent::getArgSVal(unsigned Index) const {
|
||||
|
|
@ -535,12 +535,8 @@ const ConstructionContext *CallEvent::getConstructionContext() const {
|
|||
}
|
||||
|
||||
const CallEventRef<> CallEvent::getCaller() const {
|
||||
const auto *CallLocationContext = this->getLocationContext();
|
||||
if (!CallLocationContext || CallLocationContext->inTopFrame())
|
||||
return nullptr;
|
||||
|
||||
const auto *CallSF = CallLocationContext->getStackFrame();
|
||||
if (!CallSF)
|
||||
const auto *CallSF = this->getStackFrame();
|
||||
if (!CallSF || CallSF->inTopFrame())
|
||||
return nullptr;
|
||||
|
||||
CallEventManager &CEMgr = State->getStateManager().getCallEventManager();
|
||||
|
|
@ -561,10 +557,10 @@ std::optional<SVal> CallEvent::getReturnValueUnderConstruction() const {
|
|||
|
||||
EvalCallOptions CallOpts;
|
||||
ExprEngine &Engine = getState()->getStateManager().getOwningEngine();
|
||||
unsigned NumVisitedCall = Engine.getNumVisited(
|
||||
getLocationContext(), getCFGElementRef().getParent());
|
||||
unsigned NumVisitedCall =
|
||||
Engine.getNumVisited(getStackFrame(), getCFGElementRef().getParent());
|
||||
SVal RetVal = Engine.computeObjectUnderConstruction(
|
||||
getOriginExpr(), getState(), NumVisitedCall, getLocationContext(), CC,
|
||||
getOriginExpr(), getState(), NumVisitedCall, getStackFrame(), CC,
|
||||
CallOpts);
|
||||
return RetVal;
|
||||
}
|
||||
|
|
@ -584,8 +580,7 @@ RuntimeDefinition AnyFunctionCall::getRuntimeDefinition() const {
|
|||
// Note that the AnalysisDeclContext will have the FunctionDecl with
|
||||
// the definition (if one exists).
|
||||
AnalysisDeclContext *AD =
|
||||
getLocationContext()->getAnalysisDeclContext()->
|
||||
getManager()->getContext(FD);
|
||||
getStackFrame()->getAnalysisDeclContext()->getManager()->getContext(FD);
|
||||
bool IsAutosynthesized;
|
||||
Stmt* Body = AD->getBody(IsAutosynthesized);
|
||||
LLVM_DEBUG({
|
||||
|
|
@ -985,9 +980,9 @@ void AnyCXXConstructorCall::getInitialStackFrameContents(
|
|||
}
|
||||
|
||||
const StackFrame *CXXInheritedConstructorCall::getInheritingStackFrame() const {
|
||||
const StackFrame *SF = getLocationContext()->getStackFrame();
|
||||
const StackFrame *SF = getStackFrame();
|
||||
while (isa<CXXInheritedCtorInitExpr>(SF->getCallSite()))
|
||||
SF = SF->getParent()->getStackFrame();
|
||||
SF = SF->getParent();
|
||||
return SF;
|
||||
}
|
||||
|
||||
|
|
@ -1049,7 +1044,7 @@ SVal ObjCMethodCall::getReceiverSVal() const {
|
|||
// An instance message with no expression means we are sending to super.
|
||||
// In this case the object reference is the same as 'self'.
|
||||
assert(getOriginExpr()->getReceiverKind() == ObjCMessageExpr::SuperInstance);
|
||||
SVal SelfVal = getState()->getSelfSVal(getLocationContext());
|
||||
SVal SelfVal = getState()->getSelfSVal(getStackFrame());
|
||||
assert(SelfVal.isValid() && "Calling super but not in ObjC method");
|
||||
return SelfVal;
|
||||
}
|
||||
|
|
@ -1063,7 +1058,7 @@ bool ObjCMethodCall::isReceiverSelfOrSuper() const {
|
|||
return false;
|
||||
|
||||
SVal RecVal = getSVal(getOriginExpr()->getInstanceReceiver());
|
||||
SVal SelfVal = getState()->getSelfSVal(getLocationContext());
|
||||
SVal SelfVal = getState()->getSelfSVal(getStackFrame());
|
||||
|
||||
return (RecVal == SelfVal);
|
||||
}
|
||||
|
|
@ -1102,7 +1097,7 @@ getSyntacticFromForPseudoObjectExpr(const PseudoObjectExpr *POE) {
|
|||
ObjCMessageKind ObjCMethodCall::getMessageKind() const {
|
||||
if (!Data) {
|
||||
// Find the parent, ignoring implicit casts.
|
||||
const ParentMap &PM = getLocationContext()->getParentMap();
|
||||
const ParentMap &PM = getStackFrame()->getParentMap();
|
||||
const Stmt *S = PM.getParentIgnoreParenCasts(getOriginExpr());
|
||||
|
||||
// Check if parent is a PseudoObjectExpr.
|
||||
|
|
@ -1345,7 +1340,7 @@ RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const {
|
|||
// instance (not class).
|
||||
if (ReceiverT->isObjCClass()) {
|
||||
|
||||
SVal SelfVal = getState()->getSelfSVal(getLocationContext());
|
||||
SVal SelfVal = getState()->getSelfSVal(getStackFrame());
|
||||
// For [self classMethod], return compiler visible declaration.
|
||||
if (Receiver == SelfVal.getAsRegion()) {
|
||||
return RuntimeDefinition(findDefiningRedecl(E->getMethodDecl()));
|
||||
|
|
@ -1439,41 +1434,41 @@ CallEventManager::CallEventManager(llvm::BumpPtrAllocator &alloc)
|
|||
|
||||
CallEventRef<>
|
||||
CallEventManager::getSimpleCall(const CallExpr *CE, ProgramStateRef State,
|
||||
const LocationContext *LCtx,
|
||||
const StackFrame *SF,
|
||||
CFGBlock::ConstCFGElementRef ElemRef) {
|
||||
if (const auto *MCE = dyn_cast<CXXMemberCallExpr>(CE))
|
||||
return create<CXXMemberCall>(MCE, State, LCtx, ElemRef);
|
||||
return create<CXXMemberCall>(MCE, State, SF, ElemRef);
|
||||
|
||||
if (const auto *OpCE = dyn_cast<CXXOperatorCallExpr>(CE)) {
|
||||
const FunctionDecl *DirectCallee = OpCE->getDirectCallee();
|
||||
if (const auto *MD = dyn_cast<CXXMethodDecl>(DirectCallee)) {
|
||||
if (MD->isImplicitObjectMemberFunction())
|
||||
return create<CXXMemberOperatorCall>(OpCE, State, LCtx, ElemRef);
|
||||
return create<CXXMemberOperatorCall>(OpCE, State, SF, ElemRef);
|
||||
if (MD->isStatic())
|
||||
return create<CXXStaticOperatorCall>(OpCE, State, LCtx, ElemRef);
|
||||
return create<CXXStaticOperatorCall>(OpCE, State, SF, ElemRef);
|
||||
}
|
||||
|
||||
} else if (CE->getCallee()->getType()->isBlockPointerType()) {
|
||||
return create<BlockCall>(CE, State, LCtx, ElemRef);
|
||||
return create<BlockCall>(CE, State, SF, 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, ElemRef);
|
||||
return create<SimpleFunctionCall>(CE, State, SF, ElemRef);
|
||||
}
|
||||
|
||||
CallEventRef<> CallEventManager::getCaller(const StackFrame *CalleeSF,
|
||||
ProgramStateRef State) {
|
||||
const LocationContext *ParentCtx = CalleeSF->getParent();
|
||||
const LocationContext *CallerCtx = ParentCtx->getStackFrame();
|
||||
const StackFrame *ParentSF = CalleeSF->getParent();
|
||||
const StackFrame *CallerSF = ParentSF;
|
||||
CFGBlock::ConstCFGElementRef ElemRef = {CalleeSF->getCallSiteBlock(),
|
||||
CalleeSF->getIndex()};
|
||||
assert(CallerCtx && "This should not be used for top-level stack frames");
|
||||
assert(CallerSF && "This should not be used for top-level stack frames");
|
||||
|
||||
const Expr *CallSite = CalleeSF->getCallSite();
|
||||
|
||||
if (CallSite) {
|
||||
if (CallEventRef<> Out = getCall(CallSite, State, CallerCtx, ElemRef))
|
||||
if (CallEventRef<> Out = getCall(CallSite, State, CallerSF, ElemRef))
|
||||
return Out;
|
||||
|
||||
SValBuilder &SVB = State->getStateManager().getSValBuilder();
|
||||
|
|
@ -1482,11 +1477,11 @@ CallEventRef<> CallEventManager::getCaller(const StackFrame *CalleeSF,
|
|||
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, CallerSF,
|
||||
ElemRef);
|
||||
if (const auto *CIE = dyn_cast<CXXInheritedCtorInitExpr>(CallSite))
|
||||
return getCXXInheritedConstructorCall(CIE, ThisVal.getAsRegion(), State,
|
||||
CallerCtx, ElemRef);
|
||||
CallerSF, ElemRef);
|
||||
// All other cases are handled by getCall.
|
||||
llvm_unreachable("This is not an inlineable statement");
|
||||
}
|
||||
|
|
@ -1514,20 +1509,20 @@ CallEventRef<> CallEventManager::getCaller(const StackFrame *CalleeSF,
|
|||
|
||||
return getCXXDestructorCall(Dtor, Trigger, ThisVal.getAsRegion(),
|
||||
E.getAs<CFGBaseDtor>().has_value(), State,
|
||||
CallerCtx, ElemRef);
|
||||
CallerSF, ElemRef);
|
||||
}
|
||||
|
||||
CallEventRef<> CallEventManager::getCall(const Stmt *S, ProgramStateRef State,
|
||||
const LocationContext *LC,
|
||||
const StackFrame *SF,
|
||||
CFGBlock::ConstCFGElementRef ElemRef) {
|
||||
if (const auto *CE = dyn_cast<CallExpr>(S)) {
|
||||
return getSimpleCall(CE, State, LC, ElemRef);
|
||||
return getSimpleCall(CE, State, SF, ElemRef);
|
||||
} else if (const auto *NE = dyn_cast<CXXNewExpr>(S)) {
|
||||
return getCXXAllocatorCall(NE, State, LC, ElemRef);
|
||||
return getCXXAllocatorCall(NE, State, SF, ElemRef);
|
||||
} else if (const auto *DE = dyn_cast<CXXDeleteExpr>(S)) {
|
||||
return getCXXDeallocatorCall(DE, State, LC, ElemRef);
|
||||
return getCXXDeallocatorCall(DE, State, SF, ElemRef);
|
||||
} else if (const auto *ME = dyn_cast<ObjCMessageExpr>(S)) {
|
||||
return getObjCMethodCall(ME, State, LC, ElemRef);
|
||||
return getObjCMethodCall(ME, State, SF, ElemRef);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -164,8 +164,8 @@ std::string checkerScopeName(StringRef Name, const CheckerBackend *Checker) {
|
|||
// FIXME: Remove respondsToCallback from CheckerContext;
|
||||
ProgramPoint::Kind K = IsPreVisit ? ProgramPoint::PreStmtKind :
|
||||
ProgramPoint::PostStmtKind;
|
||||
const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
|
||||
Pred->getLocationContext(), checkFn.Checker);
|
||||
const ProgramPoint &L = ProgramPoint::getProgramPoint(
|
||||
S, K, Pred->getStackFrame(), checkFn.Checker);
|
||||
CheckerContext C(Bldr, Eng, Pred, L, WasInlined);
|
||||
checkFn(S, C);
|
||||
}
|
||||
|
|
@ -338,10 +338,8 @@ namespace {
|
|||
llvm::TimeTraceScope TimeScope(checkerScopeName("Loc", checkFn.Checker));
|
||||
ProgramPoint::Kind K = IsLoad ? ProgramPoint::PreLoadKind :
|
||||
ProgramPoint::PreStoreKind;
|
||||
const ProgramPoint &L =
|
||||
ProgramPoint::getProgramPoint(NodeEx, K,
|
||||
Pred->getLocationContext(),
|
||||
checkFn.Checker);
|
||||
const ProgramPoint &L = ProgramPoint::getProgramPoint(
|
||||
NodeEx, K, Pred->getStackFrame(), checkFn.Checker);
|
||||
CheckerContext C(Bldr, Eng, Pred, L);
|
||||
checkFn(Loc, IsLoad, BoundEx, C);
|
||||
}
|
||||
|
|
@ -515,7 +513,7 @@ void CheckerManager::runCheckersForEndFunction(ExplodedNodeSet &Dst,
|
|||
NodeBuilder Bldr(Pred, Dst, Eng.getBuilderContext());
|
||||
for (const auto &checkFn : EndFunctionCheckers) {
|
||||
const ProgramPoint &L =
|
||||
FunctionExitPoint(RS, Pred->getLocationContext(), checkFn.Checker);
|
||||
FunctionExitPoint(RS, Pred->getStackFrame(), checkFn.Checker);
|
||||
CheckerContext C(Bldr, Eng, Pred, L);
|
||||
llvm::TimeTraceScope TimeScope(checkerScopeName("End", checkFn.Checker));
|
||||
checkFn(RS, C);
|
||||
|
|
@ -542,8 +540,8 @@ namespace {
|
|||
NodeBuilder &Bldr, ExplodedNode *Pred) {
|
||||
llvm::TimeTraceScope TimeScope(
|
||||
checkerScopeName("BranchCond", checkFn.Checker));
|
||||
ProgramPoint L = PostCondition(Condition, Pred->getLocationContext(),
|
||||
checkFn.Checker);
|
||||
ProgramPoint L =
|
||||
PostCondition(Condition, Pred->getStackFrame(), checkFn.Checker);
|
||||
CheckerContext C(Bldr, Eng, Pred, L);
|
||||
checkFn(Condition, C);
|
||||
}
|
||||
|
|
@ -587,7 +585,7 @@ namespace {
|
|||
llvm::TimeTraceScope TimeScope(
|
||||
checkerScopeName("Allocator", checkFn.Checker));
|
||||
ProgramPoint L = PostAllocatorCall(
|
||||
Call.getOriginExpr(), Pred->getLocationContext(), checkFn.Checker);
|
||||
Call.getOriginExpr(), Pred->getStackFrame(), checkFn.Checker);
|
||||
CheckerContext C(Bldr, Eng, Pred, L, WasInlined);
|
||||
checkFn(cast<CXXAllocatorCall>(*Call.cloneWithState(Pred->getState())),
|
||||
C);
|
||||
|
|
@ -638,8 +636,8 @@ namespace {
|
|||
NodeBuilder &Bldr, ExplodedNode *Pred) {
|
||||
llvm::TimeTraceScope TimeScope(
|
||||
checkerScopeName("DeadSymbols", checkFn.Checker));
|
||||
const ProgramPoint &L = ProgramPoint::getProgramPoint(S, ProgarmPointKind,
|
||||
Pred->getLocationContext(), checkFn.Checker);
|
||||
const ProgramPoint &L = ProgramPoint::getProgramPoint(
|
||||
S, ProgarmPointKind, Pred->getStackFrame(), checkFn.Checker);
|
||||
CheckerContext C(Bldr, Eng, Pred, L);
|
||||
|
||||
// Note, do not pass the statement to the checkers without letting them
|
||||
|
|
@ -664,20 +662,18 @@ void CheckerManager::runCheckersForDeadSymbols(ExplodedNodeSet &Dst,
|
|||
}
|
||||
|
||||
/// Run checkers for region changes.
|
||||
ProgramStateRef
|
||||
CheckerManager::runCheckersForRegionChanges(ProgramStateRef state,
|
||||
const InvalidatedSymbols *invalidated,
|
||||
ArrayRef<const MemRegion *> ExplicitRegions,
|
||||
ArrayRef<const MemRegion *> Regions,
|
||||
const LocationContext *LCtx,
|
||||
const CallEvent *Call) {
|
||||
ProgramStateRef CheckerManager::runCheckersForRegionChanges(
|
||||
ProgramStateRef state, const InvalidatedSymbols *invalidated,
|
||||
ArrayRef<const MemRegion *> ExplicitRegions,
|
||||
ArrayRef<const MemRegion *> Regions, const StackFrame *SF,
|
||||
const CallEvent *Call) {
|
||||
for (const auto &RegionChangesChecker : RegionChangesCheckers) {
|
||||
// If any checker declares the state infeasible (or if it starts that way),
|
||||
// bail out.
|
||||
if (!state)
|
||||
return nullptr;
|
||||
state = RegionChangesChecker(state, invalidated, ExplicitRegions, Regions,
|
||||
LCtx, Call);
|
||||
SF, Call);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
|
@ -739,7 +735,7 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
|
|||
// to any Expr.
|
||||
ProgramPoint L = ProgramPoint::getProgramPoint(
|
||||
UpdatedCall->getOriginExpr(), ProgramPoint::PostStmtKind,
|
||||
Pred->getLocationContext(), EvalCallChecker.Checker);
|
||||
Pred->getStackFrame(), EvalCallChecker.Checker);
|
||||
bool evaluated = false;
|
||||
{ // CheckerContext generates transitions (populates checkDest) on
|
||||
// destruction, so introduce the scope to make sure it gets properly
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h"
|
||||
#include "PrettyStackTraceLocationContext.h"
|
||||
#include "PrettyStackTraceStackFrame.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/AST/Stmt.h"
|
||||
|
|
@ -84,42 +84,41 @@ void CoreEngine::setBlockCounter(BlockCounter C) {
|
|||
}
|
||||
|
||||
/// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps.
|
||||
bool CoreEngine::ExecuteWorkList(const LocationContext *L, unsigned MaxSteps,
|
||||
bool CoreEngine::ExecuteWorkList(const StackFrame *SF, unsigned MaxSteps,
|
||||
ProgramStateRef InitState) {
|
||||
if (G.empty()) {
|
||||
assert(!G.getRoot() && "empty graph must not have a root node");
|
||||
// Initialize the analysis by constructing the root if there are no nodes.
|
||||
|
||||
const CFGBlock *Entry = &(L->getCFG()->getEntry());
|
||||
const CFGBlock *Entry = &(SF->getCFG()->getEntry());
|
||||
|
||||
assert(Entry->empty() && "Entry block must be empty.");
|
||||
|
||||
assert(Entry->succ_size() == 1 && "Entry block must have 1 successor.");
|
||||
|
||||
// Mark the entry block as visited.
|
||||
FunctionSummaries->markVisitedBasicBlock(Entry->getBlockID(),
|
||||
L->getDecl(),
|
||||
L->getCFG()->getNumBlockIDs());
|
||||
FunctionSummaries->markVisitedBasicBlock(Entry->getBlockID(), SF->getDecl(),
|
||||
SF->getCFG()->getNumBlockIDs());
|
||||
|
||||
// Get the solitary successor.
|
||||
const CFGBlock *Succ = *(Entry->succ_begin());
|
||||
|
||||
// Construct an edge representing the
|
||||
// starting location in the function.
|
||||
BlockEdge StartLoc(Entry, Succ, L);
|
||||
BlockEdge StartLoc(Entry, Succ, SF);
|
||||
|
||||
// Set the current block counter to being empty.
|
||||
setBlockCounter(BCounterFactory.GetEmptyCounter());
|
||||
|
||||
if (!InitState)
|
||||
InitState = ExprEng.getInitialState(L);
|
||||
InitState = ExprEng.getInitialState(SF);
|
||||
|
||||
bool IsNew;
|
||||
ExplodedNode *Node = G.getNode(StartLoc, InitState, false, &IsNew);
|
||||
assert(IsNew);
|
||||
G.designateAsRoot(Node);
|
||||
|
||||
ExprEng.setCurrLocationContextAndBlock(Node->getLocationContext(), Succ);
|
||||
ExprEng.setCurrStackFrameAndBlock(Node->getStackFrame(), Succ);
|
||||
|
||||
ExplodedNodeSet DstBegin;
|
||||
ExprEng.processBeginOfFunction(Node, DstBegin, StartLoc);
|
||||
|
|
@ -201,7 +200,7 @@ static llvm::TimeTraceMetadata timeTraceMetadata(const ExplodedNode *Pred,
|
|||
auto SLoc = Loc.getSourceLocation();
|
||||
if (!SLoc)
|
||||
return llvm::TimeTraceMetadata{std::move(Detail), ""};
|
||||
const auto &SM = Pred->getLocationContext()
|
||||
const auto &SM = Pred->getStackFrame()
|
||||
->getAnalysisDeclContext()
|
||||
->getASTContext()
|
||||
.getSourceManager();
|
||||
|
|
@ -216,14 +215,14 @@ void CoreEngine::dispatchWorkItem(ExplodedNode *Pred, ProgramPoint Loc,
|
|||
llvm::TimeTraceScope tcs{timeTraceScopeName(Loc), [Loc, Pred]() {
|
||||
return timeTraceMetadata(Pred, Loc);
|
||||
}};
|
||||
PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext());
|
||||
PrettyStackTraceStackFrame CrashInfo(Pred->getStackFrame());
|
||||
|
||||
// This work item is not necessarily related to the previous one, so
|
||||
// the old current LocationContext and Block is no longer relevant.
|
||||
// The new current LocationContext and Block should be set soon, but this
|
||||
// the old current StackFrame and Block is no longer relevant.
|
||||
// The new current StackFrame and Block should be set soon, but this
|
||||
// guarantees that buggy access before that will trigger loud crashes instead
|
||||
// of silently using stale data.
|
||||
ExprEng.resetCurrLocationContextAndBlock();
|
||||
ExprEng.resetCurrStackFrameAndBlock();
|
||||
|
||||
// Dispatch on the location type.
|
||||
switch (Loc.getKind()) {
|
||||
|
|
@ -268,13 +267,12 @@ void CoreEngine::dispatchWorkItem(ExplodedNode *Pred, ProgramPoint Loc,
|
|||
|
||||
void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) {
|
||||
const CFGBlock *Blk = L.getDst();
|
||||
ExprEng.setCurrLocationContextAndBlock(Pred->getLocationContext(), Blk);
|
||||
ExprEng.setCurrStackFrameAndBlock(Pred->getStackFrame(), Blk);
|
||||
|
||||
// Mark this block as visited.
|
||||
const LocationContext *LC = Pred->getLocationContext();
|
||||
FunctionSummaries->markVisitedBasicBlock(Blk->getBlockID(),
|
||||
LC->getDecl(),
|
||||
LC->getCFG()->getNumBlockIDs());
|
||||
const StackFrame *SF = Pred->getStackFrame();
|
||||
FunctionSummaries->markVisitedBasicBlock(Blk->getBlockID(), SF->getDecl(),
|
||||
SF->getCFG()->getNumBlockIDs());
|
||||
|
||||
// Display a prunable path note to the user if it's a virtual bases branch
|
||||
// and we're taking the path that skips virtual base constructors.
|
||||
|
|
@ -295,7 +293,7 @@ void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) {
|
|||
}
|
||||
|
||||
// Check if we are entering the EXIT block.
|
||||
const CFGBlock &ExitBlk = L.getLocationContext()->getCFG()->getExit();
|
||||
const CFGBlock &ExitBlk = L.getStackFrame()->getCFG()->getExit();
|
||||
if (Blk == &ExitBlk) {
|
||||
assert(ExitBlk.empty() && "EXIT block cannot contain Stmts.");
|
||||
|
||||
|
|
@ -312,7 +310,7 @@ void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) {
|
|||
}
|
||||
|
||||
ExplodedNodeSet CheckerNodes;
|
||||
BlockEntrance BE(L.getSrc(), L.getDst(), Pred->getLocationContext());
|
||||
BlockEntrance BE(L.getSrc(), L.getDst(), Pred->getStackFrame());
|
||||
ExprEng.runCheckersForBlockEntrance(BE, Pred, CheckerNodes);
|
||||
|
||||
// Process the final state transition.
|
||||
|
|
@ -325,7 +323,7 @@ void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) {
|
|||
}
|
||||
|
||||
// Call into the ExprEngine to process entering the CFGBlock.
|
||||
BlockEntrance BE(L.getSrc(), L.getDst(), Pred->getLocationContext());
|
||||
BlockEntrance BE(L.getSrc(), L.getDst(), Pred->getStackFrame());
|
||||
ExplodedNodeSet DstNodes;
|
||||
NodeBuilder Builder(Pred, DstNodes, ExprEng.getBuilderContext());
|
||||
ExprEng.processCFGBlockEntrance(L, BE, Builder, Pred);
|
||||
|
|
@ -347,17 +345,15 @@ void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) {
|
|||
void CoreEngine::HandleBlockEntrance(const BlockEntrance &L,
|
||||
ExplodedNode *Pred) {
|
||||
// Increment the block counter.
|
||||
const LocationContext *LC = Pred->getLocationContext();
|
||||
const StackFrame *SF = Pred->getStackFrame();
|
||||
unsigned BlockId = L.getBlock()->getBlockID();
|
||||
BlockCounter Counter = WList->getBlockCounter();
|
||||
Counter = BCounterFactory.IncrementCount(Counter, LC->getStackFrame(),
|
||||
BlockId);
|
||||
Counter = BCounterFactory.IncrementCount(Counter, SF, BlockId);
|
||||
setBlockCounter(Counter);
|
||||
|
||||
// Process the entrance of the block.
|
||||
if (std::optional<CFGElement> E = L.getFirstElement()) {
|
||||
ExprEng.setCurrLocationContextAndBlock(Pred->getLocationContext(),
|
||||
L.getBlock());
|
||||
ExprEng.setCurrStackFrameAndBlock(Pred->getStackFrame(), L.getBlock());
|
||||
ExprEng.processCFGElement(*E, Pred, 0);
|
||||
} else
|
||||
HandleBlockExit(L.getBlock(), Pred);
|
||||
|
|
@ -365,7 +361,7 @@ void CoreEngine::HandleBlockEntrance(const BlockEntrance &L,
|
|||
|
||||
void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) {
|
||||
if (const Stmt *Term = B->getTerminatorStmt()) {
|
||||
ExprEng.setCurrLocationContextAndBlock(Pred->getLocationContext(), B);
|
||||
ExprEng.setCurrStackFrameAndBlock(Pred->getStackFrame(), B);
|
||||
|
||||
switch (Term->getStmtClass()) {
|
||||
default:
|
||||
|
|
@ -403,7 +399,7 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) {
|
|||
// Our logic for EH analysis can certainly be improved.
|
||||
for (const CFGBlock *Succ : B->succs()) {
|
||||
if (Succ) {
|
||||
BlockEdge BE(B, Succ, Pred->getLocationContext());
|
||||
BlockEdge BE(B, Succ, Pred->getStackFrame());
|
||||
if (ExplodedNode *N = makeNode(BE, Pred->State, Pred))
|
||||
WList->enqueue(N);
|
||||
}
|
||||
|
|
@ -484,14 +480,13 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) {
|
|||
assert(B->succ_size() == 1 &&
|
||||
"Blocks with no terminator should have at most 1 successor.");
|
||||
|
||||
BlockEdge BE(B, *(B->succ_begin()), Pred->getLocationContext());
|
||||
BlockEdge BE(B, *(B->succ_begin()), Pred->getStackFrame());
|
||||
if (ExplodedNode *N = makeNode(BE, Pred->State, Pred))
|
||||
WList->enqueue(N);
|
||||
}
|
||||
|
||||
void CoreEngine::HandleCallEnter(const CallEnter &CE, ExplodedNode *Pred) {
|
||||
ExprEng.setCurrLocationContextAndBlock(Pred->getLocationContext(),
|
||||
CE.getEntry());
|
||||
ExprEng.setCurrStackFrameAndBlock(Pred->getStackFrame(), CE.getEntry());
|
||||
ExprEng.processCallEnter(CE, Pred);
|
||||
}
|
||||
|
||||
|
|
@ -541,20 +536,20 @@ void CoreEngine::HandlePostStmt(const CFGBlock *B, unsigned StmtIdx,
|
|||
if (StmtIdx == B->size())
|
||||
HandleBlockExit(B, Pred);
|
||||
else {
|
||||
ExprEng.setCurrLocationContextAndBlock(Pred->getLocationContext(), B);
|
||||
ExprEng.setCurrStackFrameAndBlock(Pred->getStackFrame(), B);
|
||||
ExprEng.processCFGElement((*B)[StmtIdx], Pred, StmtIdx);
|
||||
}
|
||||
}
|
||||
|
||||
void CoreEngine::HandleVirtualBaseBranch(const CFGBlock *B,
|
||||
ExplodedNode *Pred) {
|
||||
const LocationContext *LCtx = Pred->getLocationContext();
|
||||
if (const auto *CallerCtor = dyn_cast_or_null<CXXConstructExpr>(
|
||||
LCtx->getStackFrame()->getCallSite())) {
|
||||
const StackFrame *SF = Pred->getStackFrame();
|
||||
if (const auto *CallerCtor =
|
||||
dyn_cast_or_null<CXXConstructExpr>(SF->getCallSite())) {
|
||||
switch (CallerCtor->getConstructionKind()) {
|
||||
case CXXConstructionKind::NonVirtualBase:
|
||||
case CXXConstructionKind::VirtualBase: {
|
||||
BlockEdge Loc(B, *B->succ_begin(), LCtx);
|
||||
BlockEdge Loc(B, *B->succ_begin(), SF);
|
||||
HandleBlockEdge(Loc, Pred);
|
||||
return;
|
||||
}
|
||||
|
|
@ -565,7 +560,7 @@ void CoreEngine::HandleVirtualBaseBranch(const CFGBlock *B,
|
|||
|
||||
// We either don't see a parent stack frame because we're in the top frame,
|
||||
// or the parent stack frame doesn't initialize our virtual bases.
|
||||
BlockEdge Loc(B, *(B->succ_begin() + 1), LCtx);
|
||||
BlockEdge Loc(B, *(B->succ_begin() + 1), SF);
|
||||
HandleBlockEdge(Loc, Pred);
|
||||
}
|
||||
|
||||
|
|
@ -614,7 +609,7 @@ void CoreEngine::enqueueStmtNode(ExplodedNode *N,
|
|||
|
||||
// At this point, we know we're processing a normal statement.
|
||||
CFGStmt CS = (*Block)[Idx].castAs<CFGStmt>();
|
||||
PostStmt Loc(CS.getStmt(), N->getLocationContext());
|
||||
PostStmt Loc(CS.getStmt(), N->getStackFrame());
|
||||
|
||||
if (Loc == N->getLocation().withTag(nullptr)) {
|
||||
// Note: 'N' should be a fresh node because otherwise it shouldn't be
|
||||
|
|
@ -632,10 +627,9 @@ void CoreEngine::enqueueStmtNode(ExplodedNode *N,
|
|||
std::optional<unsigned>
|
||||
CoreEngine::getCompletedIterationCount(const CFGBlock *B,
|
||||
ExplodedNode *Pred) const {
|
||||
const LocationContext *LC = Pred->getLocationContext();
|
||||
const StackFrame *SF = Pred->getStackFrame();
|
||||
BlockCounter Counter = WList->getBlockCounter();
|
||||
unsigned BlockCount =
|
||||
Counter.getNumVisited(LC->getStackFrame(), B->getBlockID());
|
||||
unsigned BlockCount = Counter.getNumVisited(SF, B->getBlockID());
|
||||
|
||||
const Stmt *Term = B->getTerminatorStmt();
|
||||
if (isa<ForStmt, WhileStmt, CXXForRangeStmt>(Term)) {
|
||||
|
|
@ -666,12 +660,12 @@ void CoreEngine::enqueueStmtNodes(ExplodedNodeSet &Set, const CFGBlock *Block,
|
|||
|
||||
void CoreEngine::enqueueEndOfFunction(ExplodedNodeSet &Set, const ReturnStmt *RS) {
|
||||
for (ExplodedNode *Node : Set) {
|
||||
const LocationContext *LocCtx = Node->getLocationContext();
|
||||
const StackFrame *SF = Node->getStackFrame();
|
||||
|
||||
// If we are in an inlined call, generate CallExitBegin node.
|
||||
if (LocCtx->getParent()) {
|
||||
// Use the callee location context.
|
||||
CallExitBegin Loc(cast<StackFrame>(LocCtx), RS);
|
||||
if (SF->getParent()) {
|
||||
// Use the callee stack frame.
|
||||
CallExitBegin Loc(SF, RS);
|
||||
if (ExplodedNode *Succ = makeNode(Loc, Node->getState(), Node))
|
||||
WList->enqueue(Succ);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -63,9 +63,9 @@ static const Expr *ignoreTransparentExprs(const Expr *E) {
|
|||
return ignoreTransparentExprs(E);
|
||||
}
|
||||
|
||||
EnvironmentEntry::EnvironmentEntry(const Expr *E, const LocationContext *L)
|
||||
: std::pair<const Expr *, const StackFrame *>(
|
||||
ignoreTransparentExprs(E), L ? L->getStackFrame() : nullptr) {}
|
||||
EnvironmentEntry::EnvironmentEntry(const Expr *E, const StackFrame *SF)
|
||||
: std::pair<const Expr *, const StackFrame *>(ignoreTransparentExprs(E),
|
||||
SF) {}
|
||||
|
||||
SVal Environment::lookupExpr(const EnvironmentEntry &E) const {
|
||||
const SVal* X = ExprBindings.lookup(E);
|
||||
|
|
@ -79,7 +79,7 @@ SVal Environment::lookupExpr(const EnvironmentEntry &E) const {
|
|||
SVal Environment::getSVal(const EnvironmentEntry &Entry,
|
||||
SValBuilder& svalBuilder) const {
|
||||
const Expr *Ex = Entry.getExpr();
|
||||
const LocationContext *LCtx = Entry.getLocationContext();
|
||||
const StackFrame *SF = Entry.getStackFrame();
|
||||
|
||||
switch (Ex->getStmtClass()) {
|
||||
case Stmt::CXXBindTemporaryExprClass:
|
||||
|
|
@ -108,7 +108,7 @@ SVal Environment::getSVal(const EnvironmentEntry &Entry,
|
|||
|
||||
// Handle all other Expr* using a lookup.
|
||||
default:
|
||||
return lookupExpr(EnvironmentEntry(Ex, LCtx));
|
||||
return lookupExpr(EnvironmentEntry(Ex, SF));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -174,7 +174,7 @@ EnvironmentManager::removeDeadBindings(Environment Env,
|
|||
const EnvironmentEntry &BlkExpr = I.getKey();
|
||||
SVal X = I.getData();
|
||||
|
||||
if (SymReaper.isLive(BlkExpr.getExpr(), BlkExpr.getLocationContext())) {
|
||||
if (SymReaper.isLive(BlkExpr.getExpr(), BlkExpr.getStackFrame())) {
|
||||
// Copy the binding to the new map.
|
||||
EBMapRef = EBMapRef.add(BlkExpr, X);
|
||||
|
||||
|
|
@ -188,7 +188,7 @@ EnvironmentManager::removeDeadBindings(Environment Env,
|
|||
}
|
||||
|
||||
void Environment::printJson(raw_ostream &Out, const ASTContext &Ctx,
|
||||
const LocationContext *LCtx, const char *NL,
|
||||
const StackFrame *SF, const char *NL,
|
||||
unsigned int Space, bool IsDot) const {
|
||||
Indent(Out, Space, IsDot) << "\"environment\": ";
|
||||
|
||||
|
|
@ -198,28 +198,27 @@ void Environment::printJson(raw_ostream &Out, const ASTContext &Ctx,
|
|||
}
|
||||
|
||||
++Space;
|
||||
if (!LCtx) {
|
||||
// Find the freshest location context.
|
||||
llvm::SmallPtrSet<const LocationContext *, 16> FoundContexts;
|
||||
if (!SF) {
|
||||
// Find the freshest stack frame.
|
||||
llvm::SmallPtrSet<const StackFrame *, 16> FoundStackFrames;
|
||||
for (const auto &I : *this) {
|
||||
const LocationContext *LC = I.first.getLocationContext();
|
||||
if (FoundContexts.count(LC) == 0) {
|
||||
// This context is fresher than all other contexts so far.
|
||||
LCtx = LC;
|
||||
for (const LocationContext *LCI = LC; LCI; LCI = LCI->getParent())
|
||||
FoundContexts.insert(LCI);
|
||||
const StackFrame *CurrentSF = I.first.getStackFrame();
|
||||
if (FoundStackFrames.count(CurrentSF) == 0) {
|
||||
// This stack frame is fresher than all other stack frames so far.
|
||||
SF = CurrentSF;
|
||||
for (const StackFrame *SFI = CurrentSF; SFI; SFI = SFI->getParent())
|
||||
FoundStackFrames.insert(SFI);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(LCtx);
|
||||
assert(SF);
|
||||
|
||||
Out << "{ \"pointer\": \"" << (const void *)LCtx->getStackFrame()
|
||||
<< "\", \"items\": [" << NL;
|
||||
Out << "{ \"pointer\": \"" << (const void *)SF << "\", \"items\": [" << NL;
|
||||
PrintingPolicy PP = Ctx.getPrintingPolicy();
|
||||
|
||||
LCtx->printJson(Out, NL, Space, IsDot, [&](const LocationContext *LC) {
|
||||
// LCtx items begin
|
||||
SF->printJson(Out, NL, Space, IsDot, [&](const StackFrame *SF) {
|
||||
// SF items begin
|
||||
bool HasItem = false;
|
||||
unsigned int InnerSpace = Space + 1;
|
||||
|
||||
|
|
@ -227,7 +226,7 @@ void Environment::printJson(raw_ostream &Out, const ASTContext &Ctx,
|
|||
BindingsTy::iterator LastI = ExprBindings.end();
|
||||
for (BindingsTy::iterator I = ExprBindings.begin(); I != ExprBindings.end();
|
||||
++I) {
|
||||
if (I->first.getLocationContext() != LC)
|
||||
if (I->first.getStackFrame() != SF)
|
||||
continue;
|
||||
|
||||
if (!HasItem) {
|
||||
|
|
@ -244,7 +243,7 @@ void Environment::printJson(raw_ostream &Out, const ASTContext &Ctx,
|
|||
|
||||
for (BindingsTy::iterator I = ExprBindings.begin(); I != ExprBindings.end();
|
||||
++I) {
|
||||
if (I->first.getLocationContext() != LC)
|
||||
if (I->first.getStackFrame() != SF)
|
||||
continue;
|
||||
|
||||
const Expr *Ex = I->first.getExpr();
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) {
|
|||
// (4) There is no 'tag' for the ProgramPoint.
|
||||
// (5) The 'store' is the same as the predecessor.
|
||||
// (6) The 'GDM' is the same as the predecessor.
|
||||
// (7) The LocationContext is the same as the predecessor.
|
||||
// (7) The StackFrame is the same as the predecessor.
|
||||
// (8) Expressions that are *not* lvalue expressions.
|
||||
// (9) The PostStmt isn't for a non-consumed Stmt or Expr.
|
||||
// (10) The successor is neither a CallExpr StmtPoint nor a CallEnter or
|
||||
|
|
@ -111,7 +111,7 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) {
|
|||
ProgramStateRef state = node->getState();
|
||||
ProgramStateRef pred_state = pred->getState();
|
||||
if (state->store != pred_state->store || state->GDM != pred_state->GDM ||
|
||||
progPoint.getLocationContext() != pred->getLocationContext())
|
||||
progPoint.getStackFrame() != pred->getStackFrame())
|
||||
return false;
|
||||
|
||||
// All further checks require expressions. As per #3, we know that we have
|
||||
|
|
@ -130,7 +130,7 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) {
|
|||
// Do not collect nodes for non-consumed Stmt or Expr to ensure precise
|
||||
// diagnostic generation; specifically, so that we could anchor arrows
|
||||
// pointing to the beginning of statements (as written in code).
|
||||
const ParentMap &PM = progPoint.getLocationContext()->getParentMap();
|
||||
const ParentMap &PM = progPoint.getStackFrame()->getParentMap();
|
||||
if (!PM.isConsumedExpr(Ex))
|
||||
return false;
|
||||
|
||||
|
|
@ -292,36 +292,33 @@ const CFGBlock *ExplodedNode::getCFGBlock() const {
|
|||
// FIXME: getStmtForDiagnostics() does nasty things in order to provide
|
||||
// a valid statement for body farms, do we need this behavior here?
|
||||
if (const Stmt *S = getStmtForDiagnostics())
|
||||
return getLocationContext()
|
||||
->getAnalysisDeclContext()
|
||||
->getCFGStmtMap()
|
||||
->getBlock(S);
|
||||
return getStackFrame()->getAnalysisDeclContext()->getCFGStmtMap()->getBlock(
|
||||
S);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static const LocationContext *
|
||||
findTopAutosynthesizedParentContext(const LocationContext *LC) {
|
||||
assert(LC->getAnalysisDeclContext()->isBodyAutosynthesized());
|
||||
const LocationContext *ParentLC = LC->getParent();
|
||||
assert(ParentLC && "We don't start analysis from autosynthesized code");
|
||||
while (ParentLC->getAnalysisDeclContext()->isBodyAutosynthesized()) {
|
||||
LC = ParentLC;
|
||||
ParentLC = LC->getParent();
|
||||
assert(ParentLC && "We don't start analysis from autosynthesized code");
|
||||
static const StackFrame *
|
||||
findTopAutosynthesizedParentStackFrame(const StackFrame *SF) {
|
||||
assert(SF->getAnalysisDeclContext()->isBodyAutosynthesized());
|
||||
const StackFrame *ParentSF = SF->getParent();
|
||||
assert(ParentSF && "We don't start analysis from autosynthesized code");
|
||||
while (ParentSF->getAnalysisDeclContext()->isBodyAutosynthesized()) {
|
||||
SF = ParentSF;
|
||||
ParentSF = SF->getParent();
|
||||
assert(ParentSF && "We don't start analysis from autosynthesized code");
|
||||
}
|
||||
return LC;
|
||||
return SF;
|
||||
}
|
||||
|
||||
const Stmt *ExplodedNode::getStmtForDiagnostics() const {
|
||||
// We cannot place diagnostics on autosynthesized code.
|
||||
// Put them onto the call site through which we jumped into autosynthesized
|
||||
// code for the first time.
|
||||
const LocationContext *LC = getLocationContext();
|
||||
if (LC->getAnalysisDeclContext()->isBodyAutosynthesized()) {
|
||||
const StackFrame *SF = getStackFrame();
|
||||
if (SF->getAnalysisDeclContext()->isBodyAutosynthesized()) {
|
||||
// It must be a stack frame because we only autosynthesize functions.
|
||||
return cast<StackFrame>(findTopAutosynthesizedParentContext(LC))
|
||||
->getCallSite();
|
||||
return findTopAutosynthesizedParentStackFrame(SF)->getCallSite();
|
||||
}
|
||||
// Otherwise, see if the node's program point directly points to a statement.
|
||||
// FIXME: Refactor into a ProgramPoint method?
|
||||
|
|
@ -333,7 +330,7 @@ const Stmt *ExplodedNode::getStmtForDiagnostics() const {
|
|||
if (auto CE = P.getAs<CallEnter>())
|
||||
return CE->getCallExpr();
|
||||
if (auto CEE = P.getAs<CallExitEnd>())
|
||||
return CEE->getCalleeContext()->getCallSite();
|
||||
return CEE->getCalleeStackFrame()->getCallSite();
|
||||
if (auto PIPP = P.getAs<PostInitializer>())
|
||||
return PIPP->getInitializer()->getInit();
|
||||
if (auto CEB = P.getAs<CallExitBegin>())
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -30,10 +30,10 @@ static SVal conjureOffsetSymbolOnLocation(SVal Symbol, SVal Other,
|
|||
ConstCFGElementRef Elem, QualType Ty,
|
||||
SValBuilder &svalBuilder,
|
||||
unsigned Count,
|
||||
const LocationContext *LCtx) {
|
||||
const StackFrame *SF) {
|
||||
if (isa<Loc>(Other) && Ty->isIntegralOrEnumerationType() &&
|
||||
Symbol.isUnknown()) {
|
||||
return svalBuilder.conjureSymbolVal(Elem, LCtx, Ty, Count);
|
||||
return svalBuilder.conjureSymbolVal(Elem, SF, Ty, Count);
|
||||
}
|
||||
return Symbol;
|
||||
}
|
||||
|
|
@ -55,9 +55,9 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
|
|||
it != ei; ++it) {
|
||||
|
||||
ProgramStateRef state = (*it)->getState();
|
||||
const LocationContext *LCtx = (*it)->getLocationContext();
|
||||
SVal LeftV = state->getSVal(LHS, LCtx);
|
||||
SVal RightV = state->getSVal(RHS, LCtx);
|
||||
const StackFrame *SF = (*it)->getStackFrame();
|
||||
SVal LeftV = state->getSVal(LHS, SF);
|
||||
SVal RightV = state->getSVal(RHS, SF);
|
||||
|
||||
BinaryOperator::Opcode Op = B->getOpcode();
|
||||
|
||||
|
|
@ -66,14 +66,14 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
|
|||
// FIXME: Handle structs.
|
||||
if (RightV.isUnknown()) {
|
||||
unsigned Count = getNumVisitedCurrent();
|
||||
RightV = svalBuilder.conjureSymbolVal(nullptr, getCFGElementRef(), LCtx,
|
||||
RightV = svalBuilder.conjureSymbolVal(nullptr, getCFGElementRef(), SF,
|
||||
Count);
|
||||
}
|
||||
// Simulate the effects of a "store": bind the value of the RHS
|
||||
// to the L-Value represented by the LHS.
|
||||
SVal ExprVal = B->isGLValue() ? LeftV : RightV;
|
||||
evalStore(Tmp2, B, LHS, *it, state->BindExpr(B, LCtx, ExprVal),
|
||||
LeftV, RightV);
|
||||
evalStore(Tmp2, B, LHS, *it, state->BindExpr(B, SF, ExprVal), LeftV,
|
||||
RightV);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -86,23 +86,23 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
|
|||
unsigned Count = getNumVisitedCurrent();
|
||||
RightV = conjureOffsetSymbolOnLocation(
|
||||
RightV, LeftV, getCFGElementRef(), RHS->getType(), svalBuilder,
|
||||
Count, LCtx);
|
||||
Count, SF);
|
||||
LeftV = conjureOffsetSymbolOnLocation(LeftV, RightV, getCFGElementRef(),
|
||||
LHS->getType(), svalBuilder,
|
||||
Count, LCtx);
|
||||
Count, SF);
|
||||
}
|
||||
|
||||
// Although we don't yet model pointers-to-members, we do need to make
|
||||
// sure that the members of temporaries have a valid 'this' pointer for
|
||||
// other checks.
|
||||
if (B->getOpcode() == BO_PtrMemD)
|
||||
state = createTemporaryRegionIfNeeded(state, LCtx, LHS);
|
||||
state = createTemporaryRegionIfNeeded(state, SF, LHS);
|
||||
|
||||
// Process non-assignments except commas or short-circuited
|
||||
// logical expressions (LAnd and LOr).
|
||||
SVal Result = evalBinOp(state, Op, LeftV, RightV, B->getType());
|
||||
if (!Result.isUnknown()) {
|
||||
state = state->BindExpr(B, LCtx, Result);
|
||||
state = state->BindExpr(B, SF, Result);
|
||||
} else {
|
||||
// If we cannot evaluate the operation escape the operands.
|
||||
state = escapeValues(state, LeftV, PSK_EscapeOther);
|
||||
|
|
@ -138,8 +138,8 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
|
|||
|
||||
for (ExplodedNode *N : Tmp) {
|
||||
state = N->getState();
|
||||
const LocationContext *LCtx = N->getLocationContext();
|
||||
SVal V = state->getSVal(LHS, LCtx);
|
||||
const StackFrame *SF = N->getStackFrame();
|
||||
SVal V = state->getSVal(LHS, SF);
|
||||
|
||||
// Get the computation type.
|
||||
QualType CTy =
|
||||
|
|
@ -169,7 +169,7 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
|
|||
// expression, not the computation type, as this is the value the
|
||||
// LValue on the LHS will bind to.
|
||||
LHSVal = svalBuilder.conjureSymbolVal(/*symbolTag=*/nullptr,
|
||||
getCFGElementRef(), LCtx, LTy,
|
||||
getCFGElementRef(), SF, LTy,
|
||||
getNumVisitedCurrent());
|
||||
// However, we need to convert the symbol to the computation type.
|
||||
Result = svalBuilder.evalCast(LHSVal, CTy, LTy);
|
||||
|
|
@ -182,9 +182,9 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
|
|||
// In C++, assignment and compound assignment operators return an
|
||||
// lvalue.
|
||||
if (B->isGLValue())
|
||||
state = state->BindExpr(B, LCtx, location);
|
||||
state = state->BindExpr(B, SF, location);
|
||||
else
|
||||
state = state->BindExpr(B, LCtx, Result);
|
||||
state = state->BindExpr(B, SF, Result);
|
||||
|
||||
evalStore(Tmp2, B, LHS, N, state, location, LHSVal);
|
||||
}
|
||||
|
|
@ -201,7 +201,7 @@ void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred,
|
|||
|
||||
const BlockDecl *BD = BE->getBlockDecl();
|
||||
// Get the value of the block itself.
|
||||
SVal V = svalBuilder.getBlockPointer(BD, T, Pred->getLocationContext(),
|
||||
SVal V = svalBuilder.getBlockPointer(BD, T, Pred->getStackFrame(),
|
||||
getNumVisitedCurrent());
|
||||
|
||||
ProgramStateRef State = Pred->getState();
|
||||
|
|
@ -233,21 +233,20 @@ void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred,
|
|||
|
||||
if (capturedR != originalR) {
|
||||
SVal originalV;
|
||||
const LocationContext *LCtx = Pred->getLocationContext();
|
||||
const StackFrame *SF = Pred->getStackFrame();
|
||||
if (copyExpr) {
|
||||
originalV = State->getSVal(copyExpr, LCtx);
|
||||
originalV = State->getSVal(copyExpr, SF);
|
||||
} else {
|
||||
originalV = State->getSVal(loc::MemRegionVal(originalR));
|
||||
}
|
||||
State = State->bindLoc(loc::MemRegionVal(capturedR), originalV, LCtx);
|
||||
State = State->bindLoc(loc::MemRegionVal(capturedR), originalV, SF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ExplodedNodeSet Tmp;
|
||||
NodeBuilder Bldr(Pred, Tmp, *currBldrCtx);
|
||||
Bldr.generateNode(BE, Pred,
|
||||
State->BindExpr(BE, Pred->getLocationContext(), V),
|
||||
Bldr.generateNode(BE, Pred, State->BindExpr(BE, Pred->getStackFrame(), V),
|
||||
nullptr, ProgramPoint::PostLValueKind);
|
||||
|
||||
// FIXME: Move all post/pre visits to ::Visit().
|
||||
|
|
@ -256,9 +255,9 @@ void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred,
|
|||
|
||||
ProgramStateRef
|
||||
ExprEngine::handleLValueBitCast(ProgramStateRef state, const Expr *Ex,
|
||||
const LocationContext *LCtx, QualType T,
|
||||
QualType ExTy, const CastExpr *CastE,
|
||||
NodeBuilder &Bldr, ExplodedNode *Pred) {
|
||||
const StackFrame *SF, QualType T, QualType ExTy,
|
||||
const CastExpr *CastE, NodeBuilder &Bldr,
|
||||
ExplodedNode *Pred) {
|
||||
if (T->isLValueReferenceType()) {
|
||||
assert(!CastE->getType()->isLValueReferenceType());
|
||||
ExTy = getContext().getLValueReferenceType(ExTy);
|
||||
|
|
@ -267,14 +266,14 @@ ExprEngine::handleLValueBitCast(ProgramStateRef state, const Expr *Ex,
|
|||
ExTy = getContext().getRValueReferenceType(ExTy);
|
||||
}
|
||||
// Delegate to SValBuilder to process.
|
||||
SVal OrigV = state->getSVal(Ex, LCtx);
|
||||
SVal OrigV = state->getSVal(Ex, SF);
|
||||
SVal SimplifiedOrigV = svalBuilder.simplifySVal(state, OrigV);
|
||||
SVal V = svalBuilder.evalCast(SimplifiedOrigV, T, ExTy);
|
||||
// Negate the result if we're treating the boolean as a signed i1
|
||||
if (CastE->getCastKind() == CK_BooleanToSignedIntegral && V.isValid())
|
||||
V = svalBuilder.evalMinus(V.castAs<NonLoc>());
|
||||
|
||||
state = state->BindExpr(CastE, LCtx, V);
|
||||
state = state->BindExpr(CastE, SF, V);
|
||||
if (V.isUnknown() && !OrigV.isUnknown()) {
|
||||
state = escapeValues(state, OrigV, PSK_EscapeOther);
|
||||
}
|
||||
|
|
@ -292,8 +291,8 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
|
|||
if (CastE->getCastKind() == CK_LValueToRValue) {
|
||||
for (ExplodedNode *Node : DstPreStmt) {
|
||||
ProgramStateRef State = Node->getState();
|
||||
const LocationContext *LCtx = Node->getLocationContext();
|
||||
evalLoad(Dst, CastE, CastE, Node, State, State->getSVal(Ex, LCtx));
|
||||
const StackFrame *SF = Node->getStackFrame();
|
||||
evalLoad(Dst, CastE, CastE, Node, State, State->getSVal(Ex, SF));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -304,8 +303,8 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
|
|||
// Simulate the lvalue-to-rvalue conversion on `Ex`:
|
||||
for (ExplodedNode *Node : DstPreStmt) {
|
||||
ProgramStateRef State = Node->getState();
|
||||
const LocationContext *LCtx = Node->getLocationContext();
|
||||
evalLocation(DstEvalLoc, CastE, Ex, Node, State, State->getSVal(Ex, LCtx),
|
||||
const StackFrame *SF = Node->getStackFrame();
|
||||
evalLocation(DstEvalLoc, CastE, Ex, Node, State, State->getSVal(Ex, SF),
|
||||
true);
|
||||
}
|
||||
// Simulate the operation that actually casts the original value to a new
|
||||
|
|
@ -314,18 +313,18 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
|
|||
|
||||
for (ExplodedNode *Node : DstEvalLoc) {
|
||||
ProgramStateRef State = Node->getState();
|
||||
const LocationContext *LCtx = Node->getLocationContext();
|
||||
const StackFrame *SF = Node->getStackFrame();
|
||||
// Although `Ex` is an lvalue, it could have `Loc::ConcreteInt` kind
|
||||
// (e.g., `(int *)123456`). In such cases, there is no MemRegion
|
||||
// available and we can't get the value to be casted.
|
||||
SVal CastedV = UnknownVal();
|
||||
|
||||
if (const MemRegion *MR = State->getSVal(Ex, LCtx).getAsRegion()) {
|
||||
if (const MemRegion *MR = State->getSVal(Ex, SF).getAsRegion()) {
|
||||
SVal OrigV = State->getSVal(MR);
|
||||
CastedV = svalBuilder.evalCast(svalBuilder.simplifySVal(State, OrigV),
|
||||
CastE->getType(), Ex->getType());
|
||||
}
|
||||
State = State->BindExpr(CastE, LCtx, CastedV);
|
||||
State = State->BindExpr(CastE, SF, CastedV);
|
||||
Bldr.generateNode(CastE, Node, State);
|
||||
}
|
||||
return;
|
||||
|
|
@ -341,7 +340,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
|
|||
NodeBuilder Bldr(DstPreStmt, Dst, *currBldrCtx);
|
||||
for (ExplodedNode *Pred : DstPreStmt) {
|
||||
ProgramStateRef state = Pred->getState();
|
||||
const LocationContext *LCtx = Pred->getLocationContext();
|
||||
const StackFrame *SF = Pred->getStackFrame();
|
||||
|
||||
switch (CastE->getCastKind()) {
|
||||
case CK_LValueToRValue:
|
||||
|
|
@ -370,26 +369,25 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
|
|||
case CK_HLSLArrayRValue: {
|
||||
// Copy the SVal of Ex to CastE.
|
||||
ProgramStateRef state = Pred->getState();
|
||||
const LocationContext *LCtx = Pred->getLocationContext();
|
||||
SVal V = state->getSVal(Ex, LCtx);
|
||||
state = state->BindExpr(CastE, LCtx, V);
|
||||
const StackFrame *SF = Pred->getStackFrame();
|
||||
SVal V = state->getSVal(Ex, SF);
|
||||
state = state->BindExpr(CastE, SF, V);
|
||||
Bldr.generateNode(CastE, Pred, state);
|
||||
continue;
|
||||
}
|
||||
case CK_MemberPointerToBoolean:
|
||||
case CK_PointerToBoolean: {
|
||||
SVal V = state->getSVal(Ex, LCtx);
|
||||
SVal V = state->getSVal(Ex, SF);
|
||||
auto PTMSV = V.getAs<nonloc::PointerToMember>();
|
||||
if (PTMSV)
|
||||
V = svalBuilder.makeTruthVal(!PTMSV->isNullMemberPointer(), ExTy);
|
||||
if (V.isUndef() || PTMSV) {
|
||||
state = state->BindExpr(CastE, LCtx, V);
|
||||
state = state->BindExpr(CastE, SF, V);
|
||||
Bldr.generateNode(CastE, Pred, state);
|
||||
continue;
|
||||
}
|
||||
// Explicitly proceed with default handler for this case cascade.
|
||||
state =
|
||||
handleLValueBitCast(state, Ex, LCtx, T, ExTy, CastE, Bldr, Pred);
|
||||
state = handleLValueBitCast(state, Ex, SF, T, ExTy, CastE, Bldr, Pred);
|
||||
continue;
|
||||
}
|
||||
case CK_Dependent:
|
||||
|
|
@ -399,15 +397,14 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
|
|||
case CK_BooleanToSignedIntegral:
|
||||
case CK_IntegralToPointer:
|
||||
case CK_PointerToIntegral: {
|
||||
SVal V = state->getSVal(Ex, LCtx);
|
||||
SVal V = state->getSVal(Ex, SF);
|
||||
if (isa<nonloc::PointerToMember>(V)) {
|
||||
state = state->BindExpr(CastE, LCtx, UnknownVal());
|
||||
state = state->BindExpr(CastE, SF, UnknownVal());
|
||||
Bldr.generateNode(CastE, Pred, state);
|
||||
continue;
|
||||
}
|
||||
// Explicitly proceed with default handler for this case cascade.
|
||||
state =
|
||||
handleLValueBitCast(state, Ex, LCtx, T, ExTy, CastE, Bldr, Pred);
|
||||
state = handleLValueBitCast(state, Ex, SF, T, ExTy, CastE, Bldr, Pred);
|
||||
continue;
|
||||
}
|
||||
case CK_IntegralToBoolean:
|
||||
|
|
@ -438,33 +435,32 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
|
|||
case CK_FixedPointToBoolean:
|
||||
case CK_FixedPointToIntegral:
|
||||
case CK_IntegralToFixedPoint: {
|
||||
state =
|
||||
handleLValueBitCast(state, Ex, LCtx, T, ExTy, CastE, Bldr, Pred);
|
||||
state = handleLValueBitCast(state, Ex, SF, T, ExTy, CastE, Bldr, Pred);
|
||||
continue;
|
||||
}
|
||||
case CK_IntegralCast: {
|
||||
// Delegate to SValBuilder to process.
|
||||
SVal V = state->getSVal(Ex, LCtx);
|
||||
SVal V = state->getSVal(Ex, SF);
|
||||
if (AMgr.options.ShouldSupportSymbolicIntegerCasts)
|
||||
V = svalBuilder.evalCast(V, T, ExTy);
|
||||
else
|
||||
V = svalBuilder.evalIntegralCast(state, V, T, ExTy);
|
||||
state = state->BindExpr(CastE, LCtx, V);
|
||||
state = state->BindExpr(CastE, SF, V);
|
||||
Bldr.generateNode(CastE, Pred, state);
|
||||
continue;
|
||||
}
|
||||
case CK_DerivedToBase:
|
||||
case CK_UncheckedDerivedToBase: {
|
||||
// For DerivedToBase cast, delegate to the store manager.
|
||||
SVal val = state->getSVal(Ex, LCtx);
|
||||
SVal val = state->getSVal(Ex, SF);
|
||||
val = getStoreManager().evalDerivedToBase(val, CastE);
|
||||
state = state->BindExpr(CastE, LCtx, val);
|
||||
state = state->BindExpr(CastE, SF, val);
|
||||
Bldr.generateNode(CastE, Pred, state);
|
||||
continue;
|
||||
}
|
||||
// Handle C++ dyn_cast.
|
||||
case CK_Dynamic: {
|
||||
SVal val = state->getSVal(Ex, LCtx);
|
||||
SVal val = state->getSVal(Ex, SF);
|
||||
|
||||
// Compute the type of the result.
|
||||
QualType resultType = CastE->getType();
|
||||
|
|
@ -489,25 +485,25 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
|
|||
continue;
|
||||
} else {
|
||||
// If the cast fails on a pointer, bind to 0.
|
||||
state = state->BindExpr(CastE, LCtx,
|
||||
state = state->BindExpr(CastE, SF,
|
||||
svalBuilder.makeNullWithType(resultType));
|
||||
}
|
||||
} else {
|
||||
// If we don't know if the cast succeeded, conjure a new symbol.
|
||||
if (val.isUnknown()) {
|
||||
DefinedOrUnknownSVal NewSym = svalBuilder.conjureSymbolVal(
|
||||
/*symbolTag=*/nullptr, getCFGElementRef(), LCtx, resultType,
|
||||
/*symbolTag=*/nullptr, getCFGElementRef(), SF, resultType,
|
||||
getNumVisitedCurrent());
|
||||
state = state->BindExpr(CastE, LCtx, NewSym);
|
||||
state = state->BindExpr(CastE, SF, NewSym);
|
||||
} else
|
||||
// Else, bind to the derived region value.
|
||||
state = state->BindExpr(CastE, LCtx, val);
|
||||
state = state->BindExpr(CastE, SF, val);
|
||||
}
|
||||
Bldr.generateNode(CastE, Pred, state);
|
||||
continue;
|
||||
}
|
||||
case CK_BaseToDerived: {
|
||||
SVal val = state->getSVal(Ex, LCtx);
|
||||
SVal val = state->getSVal(Ex, SF);
|
||||
QualType resultType = CastE->getType();
|
||||
if (CastE->isGLValue())
|
||||
resultType = getContext().getPointerType(resultType);
|
||||
|
|
@ -520,34 +516,34 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
|
|||
// Failed to cast or the result is unknown, fall back to conservative.
|
||||
if (val.isUnknown()) {
|
||||
val = svalBuilder.conjureSymbolVal(
|
||||
/*symbolTag=*/nullptr, getCFGElementRef(), LCtx, resultType,
|
||||
/*symbolTag=*/nullptr, getCFGElementRef(), SF, resultType,
|
||||
getNumVisitedCurrent());
|
||||
}
|
||||
state = state->BindExpr(CastE, LCtx, val);
|
||||
state = state->BindExpr(CastE, SF, val);
|
||||
Bldr.generateNode(CastE, Pred, state);
|
||||
continue;
|
||||
}
|
||||
case CK_NullToPointer: {
|
||||
SVal V = svalBuilder.makeNullWithType(CastE->getType());
|
||||
state = state->BindExpr(CastE, LCtx, V);
|
||||
state = state->BindExpr(CastE, SF, V);
|
||||
Bldr.generateNode(CastE, Pred, state);
|
||||
continue;
|
||||
}
|
||||
case CK_NullToMemberPointer: {
|
||||
SVal V = svalBuilder.getMemberPointer(nullptr);
|
||||
state = state->BindExpr(CastE, LCtx, V);
|
||||
state = state->BindExpr(CastE, SF, V);
|
||||
Bldr.generateNode(CastE, Pred, state);
|
||||
continue;
|
||||
}
|
||||
case CK_DerivedToBaseMemberPointer:
|
||||
case CK_BaseToDerivedMemberPointer:
|
||||
case CK_ReinterpretMemberPointer: {
|
||||
SVal V = state->getSVal(Ex, LCtx);
|
||||
SVal V = state->getSVal(Ex, SF);
|
||||
if (auto PTMSV = V.getAs<nonloc::PointerToMember>()) {
|
||||
SVal CastedPTMSV =
|
||||
svalBuilder.makePointerToMember(getBasicVals().accumCXXBase(
|
||||
CastE->path(), *PTMSV, CastE->getCastKind()));
|
||||
state = state->BindExpr(CastE, LCtx, CastedPTMSV);
|
||||
state = state->BindExpr(CastE, SF, CastedPTMSV);
|
||||
Bldr.generateNode(CastE, Pred, state);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -566,9 +562,9 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
|
|||
if (CastE->isGLValue())
|
||||
resultType = getContext().getPointerType(resultType);
|
||||
SVal result = svalBuilder.conjureSymbolVal(
|
||||
/*symbolTag=*/nullptr, getCFGElementRef(), LCtx, resultType,
|
||||
/*symbolTag=*/nullptr, getCFGElementRef(), SF, resultType,
|
||||
getNumVisitedCurrent());
|
||||
state = state->BindExpr(CastE, LCtx, result);
|
||||
state = state->BindExpr(CastE, SF, result);
|
||||
Bldr.generateNode(CastE, Pred, state);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -582,23 +578,23 @@ void ExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL,
|
|||
NodeBuilder B(Pred, Dst, *currBldrCtx);
|
||||
|
||||
ProgramStateRef State = Pred->getState();
|
||||
const LocationContext *LCtx = Pred->getLocationContext();
|
||||
const StackFrame *SF = Pred->getStackFrame();
|
||||
|
||||
const Expr *Init = CL->getInitializer();
|
||||
SVal V = State->getSVal(CL->getInitializer(), LCtx);
|
||||
SVal V = State->getSVal(CL->getInitializer(), SF);
|
||||
|
||||
if (isa<CXXConstructExpr, CXXStdInitializerListExpr>(Init)) {
|
||||
// No work needed. Just pass the value up to this expression.
|
||||
} else {
|
||||
assert(isa<InitListExpr>(Init));
|
||||
Loc CLLoc = State->getLValue(CL, LCtx);
|
||||
State = State->bindLoc(CLLoc, V, LCtx);
|
||||
Loc CLLoc = State->getLValue(CL, SF);
|
||||
State = State->bindLoc(CLLoc, V, SF);
|
||||
|
||||
if (CL->isGLValue())
|
||||
V = CLLoc;
|
||||
}
|
||||
|
||||
B.generateNode(CL, Pred, State->BindExpr(CL, LCtx, V));
|
||||
B.generateNode(CL, Pred, State->BindExpr(CL, SF, V));
|
||||
}
|
||||
|
||||
void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
|
||||
|
|
@ -634,18 +630,18 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
|
|||
I!=E; ++I) {
|
||||
ExplodedNode *N = *I;
|
||||
ProgramStateRef state = N->getState();
|
||||
const LocationContext *LC = N->getLocationContext();
|
||||
const StackFrame *SF = N->getStackFrame();
|
||||
|
||||
// Decls without InitExpr are not initialized explicitly.
|
||||
if (const Expr *InitEx = VD->getInit()) {
|
||||
|
||||
// Note in the state that the initialization has occurred.
|
||||
ExplodedNode *UpdatedN = N;
|
||||
SVal InitVal = state->getSVal(InitEx, LC);
|
||||
SVal InitVal = state->getSVal(InitEx, SF);
|
||||
|
||||
assert(DS->isSingleDecl());
|
||||
if (getObjectUnderConstruction(state, DS, LC)) {
|
||||
state = finishObjectConstruction(state, DS, LC);
|
||||
if (getObjectUnderConstruction(state, DS, SF)) {
|
||||
state = finishObjectConstruction(state, DS, SF);
|
||||
// We constructed the object directly in the variable.
|
||||
// No need to bind anything.
|
||||
B.generateNode(DS, UpdatedN, state);
|
||||
|
|
@ -659,14 +655,14 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
|
|||
}
|
||||
|
||||
InitVal = svalBuilder.conjureSymbolVal(
|
||||
/*symbolTag=*/nullptr, getCFGElementRef(), LC, Ty,
|
||||
/*symbolTag=*/nullptr, getCFGElementRef(), SF, Ty,
|
||||
getNumVisitedCurrent());
|
||||
}
|
||||
|
||||
|
||||
B.takeNodes(UpdatedN);
|
||||
ExplodedNodeSet Dst2;
|
||||
evalBind(Dst2, DS, UpdatedN, state->getLValue(VD, LC), InitVal, true);
|
||||
evalBind(Dst2, DS, UpdatedN, state->getLValue(VD, SF), InitVal, true);
|
||||
B.addNodes(Dst2);
|
||||
}
|
||||
}
|
||||
|
|
@ -755,7 +751,7 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
|
|||
assert(!SrcBlock->empty());
|
||||
CFGStmt Elem = SrcBlock->rbegin()->castAs<CFGStmt>();
|
||||
const Expr *RHS = cast<Expr>(Elem.getStmt());
|
||||
SVal RHSVal = N->getState()->getSVal(RHS, Pred->getLocationContext());
|
||||
SVal RHSVal = N->getState()->getSVal(RHS, Pred->getStackFrame());
|
||||
|
||||
if (RHSVal.isUndef()) {
|
||||
X = RHSVal;
|
||||
|
|
@ -769,7 +765,7 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
|
|||
Zero, B->getType());
|
||||
}
|
||||
}
|
||||
Bldr.generateNode(B, Pred, state->BindExpr(B, Pred->getLocationContext(), X));
|
||||
Bldr.generateNode(B, Pred, state->BindExpr(B, Pred->getStackFrame(), X));
|
||||
}
|
||||
|
||||
void ExprEngine::VisitGuardedExpr(const Expr *Ex,
|
||||
|
|
@ -781,7 +777,7 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex,
|
|||
|
||||
NodeBuilder B(Pred, Dst, *currBldrCtx);
|
||||
ProgramStateRef state = Pred->getState();
|
||||
const LocationContext *LCtx = Pred->getLocationContext();
|
||||
const StackFrame *SF = Pred->getStackFrame();
|
||||
const CFGBlock *SrcBlock = nullptr;
|
||||
|
||||
// Find the predecessor block.
|
||||
|
|
@ -822,18 +818,18 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex,
|
|||
// subexpression, get its the value.
|
||||
if (ValEx == L->IgnoreParens() || ValEx == R->IgnoreParens()) {
|
||||
hasValue = true;
|
||||
V = SrcState->getSVal(ValEx, LCtx);
|
||||
V = SrcState->getSVal(ValEx, SF);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasValue)
|
||||
V = svalBuilder.conjureSymbolVal(nullptr, getCFGElementRef(), LCtx,
|
||||
V = svalBuilder.conjureSymbolVal(nullptr, getCFGElementRef(), SF,
|
||||
getNumVisitedCurrent());
|
||||
|
||||
// Generate a new node with the binding from the appropriate path.
|
||||
B.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V, true));
|
||||
B.generateNode(Ex, Pred, state->BindExpr(Ex, SF, V, true));
|
||||
}
|
||||
|
||||
void ExprEngine::
|
||||
|
|
@ -848,8 +844,7 @@ VisitOffsetOfExpr(const OffsetOfExpr *OOE,
|
|||
assert(IV.isSigned() == OOE->getType()->isSignedIntegerType());
|
||||
SVal X = svalBuilder.makeIntVal(IV);
|
||||
B.generateNode(OOE, Pred,
|
||||
Pred->getState()->BindExpr(OOE, Pred->getLocationContext(),
|
||||
X));
|
||||
Pred->getState()->BindExpr(OOE, Pred->getStackFrame(), X));
|
||||
}
|
||||
// FIXME: Handle the case where __builtin_offsetof is not a constant.
|
||||
}
|
||||
|
|
@ -890,7 +885,7 @@ VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex,
|
|||
|
||||
ProgramStateRef state = N->getState();
|
||||
state = state->BindExpr(
|
||||
Ex, N->getLocationContext(),
|
||||
Ex, N->getStackFrame(),
|
||||
svalBuilder.makeIntVal(amt.getQuantity(), Ex->getType()));
|
||||
Bldr.generateNode(Ex, N, state);
|
||||
}
|
||||
|
|
@ -909,8 +904,8 @@ void ExprEngine::handleUOExtension(ExplodedNode *N, const UnaryOperator *U,
|
|||
// subexpression.
|
||||
const Expr *Ex = U->getSubExpr()->IgnoreParens();
|
||||
ProgramStateRef state = N->getState();
|
||||
const LocationContext *LCtx = N->getLocationContext();
|
||||
Bldr.generateNode(U, N, state->BindExpr(U, LCtx, state->getSVal(Ex, LCtx)));
|
||||
const StackFrame *SF = N->getStackFrame();
|
||||
Bldr.generateNode(U, N, state->BindExpr(U, SF, state->getSVal(Ex, SF)));
|
||||
}
|
||||
|
||||
void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, ExplodedNode *Pred,
|
||||
|
|
@ -943,9 +938,8 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, ExplodedNode *Pred,
|
|||
// For all other types, UO_Real is an identity operation.
|
||||
assert (U->getType() == Ex->getType());
|
||||
ProgramStateRef state = N->getState();
|
||||
const LocationContext *LCtx = N->getLocationContext();
|
||||
Bldr.generateNode(U, N,
|
||||
state->BindExpr(U, LCtx, state->getSVal(Ex, LCtx)));
|
||||
const StackFrame *SF = N->getStackFrame();
|
||||
Bldr.generateNode(U, N, state->BindExpr(U, SF, state->getSVal(Ex, SF)));
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -958,9 +952,9 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, ExplodedNode *Pred,
|
|||
}
|
||||
// For all other types, UO_Imag returns 0.
|
||||
ProgramStateRef state = N->getState();
|
||||
const LocationContext *LCtx = N->getLocationContext();
|
||||
const StackFrame *SF = N->getStackFrame();
|
||||
SVal X = svalBuilder.makeZeroVal(Ex->getType());
|
||||
Bldr.generateNode(U, N, state->BindExpr(U, LCtx, X));
|
||||
Bldr.generateNode(U, N, state->BindExpr(U, SF, X));
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -972,9 +966,9 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, ExplodedNode *Pred,
|
|||
|
||||
if (isa<CXXMethodDecl, FieldDecl, IndirectFieldDecl>(VD)) {
|
||||
ProgramStateRef State = N->getState();
|
||||
const LocationContext *LCtx = N->getLocationContext();
|
||||
const StackFrame *SF = N->getStackFrame();
|
||||
SVal SV = svalBuilder.getMemberPointer(cast<NamedDecl>(VD));
|
||||
Bldr.generateNode(U, N, State->BindExpr(U, LCtx, SV));
|
||||
Bldr.generateNode(U, N, State->BindExpr(U, SF, SV));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -997,13 +991,13 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, ExplodedNode *Pred,
|
|||
assert (!U->isGLValue());
|
||||
const Expr *Ex = U->getSubExpr()->IgnoreParens();
|
||||
ProgramStateRef state = N->getState();
|
||||
const LocationContext *LCtx = N->getLocationContext();
|
||||
const StackFrame *SF = N->getStackFrame();
|
||||
|
||||
// Get the value of the subexpression.
|
||||
SVal V = state->getSVal(Ex, LCtx);
|
||||
SVal V = state->getSVal(Ex, SF);
|
||||
|
||||
if (V.isUnknownOrUndef()) {
|
||||
Bldr.generateNode(U, N, state->BindExpr(U, LCtx, V));
|
||||
Bldr.generateNode(U, N, state->BindExpr(U, SF, V));
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -1013,12 +1007,12 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, ExplodedNode *Pred,
|
|||
case UO_Not:
|
||||
// FIXME: Do we need to handle promotions?
|
||||
state = state->BindExpr(
|
||||
U, LCtx, svalBuilder.evalComplement(V.castAs<NonLoc>()));
|
||||
U, SF, svalBuilder.evalComplement(V.castAs<NonLoc>()));
|
||||
break;
|
||||
case UO_Minus:
|
||||
// FIXME: Do we need to handle promotions?
|
||||
state = state->BindExpr(U, LCtx,
|
||||
svalBuilder.evalMinus(V.castAs<NonLoc>()));
|
||||
state =
|
||||
state->BindExpr(U, SF, svalBuilder.evalMinus(V.castAs<NonLoc>()));
|
||||
break;
|
||||
case UO_LNot:
|
||||
// C99 6.5.3.3: "The expression !E is equivalent to (0==E)."
|
||||
|
|
@ -1037,7 +1031,7 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, ExplodedNode *Pred,
|
|||
Result = evalBinOp(state, BO_EQ, V.castAs<NonLoc>(), X, U->getType());
|
||||
}
|
||||
|
||||
state = state->BindExpr(U, LCtx, Result);
|
||||
state = state->BindExpr(U, SF, Result);
|
||||
break;
|
||||
}
|
||||
Bldr.generateNode(U, N, state);
|
||||
|
|
@ -1056,9 +1050,9 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U,
|
|||
assert (U->isIncrementDecrementOp());
|
||||
const Expr *Ex = U->getSubExpr()->IgnoreParens();
|
||||
|
||||
const LocationContext *LCtx = Pred->getLocationContext();
|
||||
const StackFrame *SF = Pred->getStackFrame();
|
||||
ProgramStateRef state = Pred->getState();
|
||||
SVal loc = state->getSVal(Ex, LCtx);
|
||||
SVal loc = state->getSVal(Ex, SF);
|
||||
|
||||
// Perform a load.
|
||||
ExplodedNodeSet Tmp;
|
||||
|
|
@ -1068,12 +1062,12 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U,
|
|||
NodeBuilder Bldr(Tmp, Dst2, *currBldrCtx);
|
||||
for (ExplodedNode *N : Tmp) {
|
||||
state = N->getState();
|
||||
assert(LCtx == N->getLocationContext());
|
||||
SVal V2_untested = state->getSVal(Ex, LCtx);
|
||||
assert(SF == N->getStackFrame());
|
||||
SVal V2_untested = state->getSVal(Ex, SF);
|
||||
|
||||
// Propagate unknown and undefined values.
|
||||
if (V2_untested.isUnknownOrUndef()) {
|
||||
state = state->BindExpr(U, LCtx, V2_untested);
|
||||
state = state->BindExpr(U, SF, V2_untested);
|
||||
|
||||
// Perform the store, so that the uninitialized value detection happens.
|
||||
Bldr.takeNodes(N);
|
||||
|
|
@ -1113,7 +1107,7 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U,
|
|||
// Conjure a new symbol if necessary to recover precision.
|
||||
if (Result.isUnknown()){
|
||||
DefinedOrUnknownSVal SymVal = svalBuilder.conjureSymbolVal(
|
||||
/*symbolTag=*/nullptr, getCFGElementRef(), LCtx,
|
||||
/*symbolTag=*/nullptr, getCFGElementRef(), SF,
|
||||
getNumVisitedCurrent());
|
||||
Result = SymVal;
|
||||
|
||||
|
|
@ -1139,9 +1133,9 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U,
|
|||
// Since the lvalue-to-rvalue conversion is explicit in the AST,
|
||||
// we bind an l-value if the operator is prefix and an lvalue (in C++).
|
||||
if (U->isGLValue())
|
||||
state = state->BindExpr(U, LCtx, loc);
|
||||
state = state->BindExpr(U, SF, loc);
|
||||
else
|
||||
state = state->BindExpr(U, LCtx, U->isPostfix() ? V2 : Result);
|
||||
state = state->BindExpr(U, SF, U->isPostfix() ? V2 : Result);
|
||||
|
||||
// Perform the store.
|
||||
Bldr.takeNodes(N);
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue