const ImplicitParamDecl *getSelfDecl() const;
const StackFrameContext *getStackFrame(LocationContext const *Parent,
- const Stmt *S,
- const CFGBlock *Blk,
- unsigned Idx);
+ const Stmt *S, const CFGBlock *Blk,
+ unsigned BlockCount, unsigned Idx);
const BlockInvocationContext *
getBlockInvocationContext(const LocationContext *parent,
// The parent block of the callsite.
const CFGBlock *Block;
+ // The number of times the 'Block' has been visited.
+ // It allows discriminating between stack frames of the same call that is
+ // called multiple times in a loop.
+ const unsigned BlockCount;
+
// The index of the callsite in the CFGBlock.
- unsigned Index;
+ const unsigned Index;
StackFrameContext(AnalysisDeclContext *ctx, const LocationContext *parent,
- const Stmt *s, const CFGBlock *blk,
- unsigned idx,
- int64_t ID)
- : LocationContext(StackFrame, ctx, parent, ID), CallSite(s),
- Block(blk), Index(idx) {}
+ const Stmt *s, const CFGBlock *blk, unsigned blockCount,
+ unsigned idx, int64_t ID)
+ : LocationContext(StackFrame, ctx, parent, ID), CallSite(s), Block(blk),
+ BlockCount(blockCount), Index(idx) {}
public:
~StackFrameContext() override = default;
static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx,
const LocationContext *parent, const Stmt *s,
- const CFGBlock *blk, unsigned idx) {
+ const CFGBlock *blk, unsigned blockCount, unsigned idx) {
ProfileCommon(ID, StackFrame, ctx, parent, s);
ID.AddPointer(blk);
+ ID.AddInteger(blockCount);
ID.AddInteger(idx);
}
const StackFrameContext *getStackFrame(AnalysisDeclContext *ctx,
const LocationContext *parent,
- const Stmt *s,
- const CFGBlock *blk, unsigned idx);
+ const Stmt *s, const CFGBlock *blk,
+ unsigned blockCount, unsigned idx);
const ScopeContext *getScope(AnalysisDeclContext *ctx,
const LocationContext *parent,
bool synthesizeBodies() const { return SynthesizeBodies; }
const StackFrameContext *getStackFrame(AnalysisDeclContext *Ctx,
- LocationContext const *Parent,
- const Stmt *S,
- const CFGBlock *Blk,
- unsigned Idx) {
- return LocContexts.getStackFrame(Ctx, Parent, S, Blk, Idx);
+ const LocationContext *Parent,
+ const Stmt *S, const CFGBlock *Blk,
+ unsigned BlockCount, unsigned Idx) {
+ return LocContexts.getStackFrame(Ctx, Parent, S, Blk, BlockCount, Idx);
}
// Get the top level stack frame.
const StackFrameContext *getStackFrame(const Decl *D) {
return LocContexts.getStackFrame(getContext(D), nullptr, nullptr, nullptr,
- 0);
+ 0, 0);
}
// Get a stack frame with parent.
StackFrameContext const *getStackFrame(const Decl *D,
- LocationContext const *Parent,
- const Stmt *S,
- const CFGBlock *Blk,
- unsigned Idx) {
- return LocContexts.getStackFrame(getContext(D), Parent, S, Blk, Idx);
+ const LocationContext *Parent,
+ const Stmt *S, const CFGBlock *Blk,
+ unsigned BlockCount, unsigned Idx) {
+ return LocContexts.getStackFrame(getContext(D), Parent, S, Blk, BlockCount,
+ Idx);
}
/// Get a reference to {@code BodyFarm} instance.
/// during analysis if the call is inlined, but it may still be useful
/// in intermediate calculations even if the call isn't inlined.
/// May fail; returns null on failure.
- const StackFrameContext *getCalleeStackFrame() const;
+ const StackFrameContext *getCalleeStackFrame(unsigned BlockCount) const;
/// Returns memory location for a parameter variable within the callee stack
/// frame. May fail; returns null on failure.
- const VarRegion *getParameterLocation(unsigned Index) const;
+ const VarRegion *getParameterLocation(unsigned Index,
+ unsigned BlockCount) const;
/// Returns true if on the current path, the argument was constructed by
/// calling a C++ constructor over it. This is an internal detail of the
const StackFrameContext *
AnalysisDeclContext::getStackFrame(LocationContext const *Parent, const Stmt *S,
- const CFGBlock *Blk, unsigned Idx) {
- return getLocationContextManager().getStackFrame(this, Parent, S, Blk, Idx);
+ const CFGBlock *Blk, unsigned BlockCount,
+ unsigned Idx) {
+ return getLocationContextManager().getStackFrame(this, Parent, S, Blk,
+ BlockCount, Idx);
}
const BlockInvocationContext *
}
void StackFrameContext::Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getAnalysisDeclContext(), getParent(), CallSite, Block, Index);
+ Profile(ID, getAnalysisDeclContext(), getParent(), CallSite, Block,
+ BlockCount, Index);
}
void ScopeContext::Profile(llvm::FoldingSetNodeID &ID) {
return L;
}
-const StackFrameContext*
-LocationContextManager::getStackFrame(AnalysisDeclContext *ctx,
- const LocationContext *parent,
- const Stmt *s,
- const CFGBlock *blk, unsigned idx) {
+const StackFrameContext *LocationContextManager::getStackFrame(
+ AnalysisDeclContext *ctx, const LocationContext *parent, const Stmt *s,
+ const CFGBlock *blk, unsigned blockCount, unsigned idx) {
llvm::FoldingSetNodeID ID;
- StackFrameContext::Profile(ID, ctx, parent, s, blk, idx);
+ StackFrameContext::Profile(ID, ctx, parent, s, blk, blockCount, idx);
void *InsertPos;
auto *L =
cast_or_null<StackFrameContext>(Contexts.FindNodeOrInsertPos(ID, InsertPos));
if (!L) {
- L = new StackFrameContext(ctx, parent, s, blk, idx, ++NewID);
+ L = new StackFrameContext(ctx, parent, s, blk, blockCount, idx, ++NewID);
Contexts.InsertNode(L, InsertPos);
}
return L;
return ADC;
}
-const StackFrameContext *CallEvent::getCalleeStackFrame() const {
+const StackFrameContext *
+CallEvent::getCalleeStackFrame(unsigned BlockCount) const {
AnalysisDeclContext *ADC = getCalleeAnalysisDeclContext();
if (!ADC)
return nullptr;
break;
assert(Idx < Sz);
- return ADC->getManager()->getStackFrame(ADC, LCtx, E, B, Idx);
+ return ADC->getManager()->getStackFrame(ADC, LCtx, E, B, BlockCount, Idx);
}
-const VarRegion *CallEvent::getParameterLocation(unsigned Index) const {
- const StackFrameContext *SFC = getCalleeStackFrame();
+const VarRegion *CallEvent::getParameterLocation(unsigned Index,
+ unsigned BlockCount) const {
+ const StackFrameContext *SFC = getCalleeStackFrame(BlockCount);
// We cannot construct a VarRegion without a stack frame.
if (!SFC)
return nullptr;
if (getKind() != CE_CXXAllocator)
if (isArgumentConstructedDirectly(Idx))
if (auto AdjIdx = getAdjustedParameterIndex(Idx))
- if (const VarRegion *VR = getParameterLocation(*AdjIdx))
+ if (const VarRegion *VR = getParameterLocation(*AdjIdx, BlockCount))
ValuesToInvalidate.push_back(loc::MemRegionVal(VR));
}
CallEventManager &CEMgr = getStateManager().getCallEventManager();
SVal V = UnknownVal();
auto getArgLoc = [&](CallEventRef<> Caller) -> Optional<SVal> {
- const LocationContext *FutureSFC = Caller->getCalleeStackFrame();
+ const LocationContext *FutureSFC =
+ Caller->getCalleeStackFrame(currBldrCtx->blockCount());
// Return early if we are unable to reliably foresee
// the future stack frame.
if (!FutureSFC)
// because this-argument is implemented as a normal argument in
// operator call expressions but not in operator declarations.
const VarRegion *VR = Caller->getParameterLocation(
- *Caller->getAdjustedParameterIndex(Idx));
+ *Caller->getAdjustedParameterIndex(Idx), currBldrCtx->blockCount());
if (!VR)
return None;
// Construct a new stack frame for the callee.
AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(D);
const StackFrameContext *CalleeSFC =
- CalleeADC->getStackFrame(ParentOfCallee, CallE,
- currBldrCtx->getBlock(),
- currStmtIdx);
+ CalleeADC->getStackFrame(ParentOfCallee, CallE, currBldrCtx->getBlock(),
+ currBldrCtx->blockCount(), currStmtIdx);
CallEnter Loc(CallE, CalleeSFC, CurLC);
for (int i = 0; i < 2; ++i)
callee(&arr[i]);
// FIXME: Should be UNKNOWN.
- clang_analyzer_eval(arr[0] == arr[1]); // expected-warning{{TRUE}}
+ clang_analyzer_eval(arr[0] == arr[1]); // expected-warning{{FALSE}}
}
void loopWithCall() {
int simple_unknown_bound_loop() {
for (int i = 2; i < getNum(); i++) {
#ifdef DFS
- clang_analyzer_numTimesReached(); // expected-warning {{10}}
+ clang_analyzer_numTimesReached(); // expected-warning {{16}}
#else
- clang_analyzer_numTimesReached(); // expected-warning {{13}}
+ clang_analyzer_numTimesReached(); // expected-warning {{8}}
#endif
}
return 0;
int nested_inlined_no_unroll1() {
int k;
for (int i = 0; i < 9; i++) {
-#ifdef ANALYZER_CM_Z3
- clang_analyzer_numTimesReached(); // expected-warning {{13}}
+#ifdef DFS
+ clang_analyzer_numTimesReached(); // expected-warning {{18}}
#else
- clang_analyzer_numTimesReached(); // expected-warning {{15}}
+ clang_analyzer_numTimesReached(); // expected-warning {{14}}
#endif
k = simple_unknown_bound_loop(); // reevaluation without inlining, splits the state as well
}
--- /dev/null
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDelete -verify %s
+
+// expected-no-diagnostics:
+// From now the profile of the 'StackFrameContext' also contains the
+// 'NodeBuilderContext::blockCount()'. With this addition we can distinguish
+// between the 'StackArgumentsSpaceRegion' of the 'P' arguments being different
+// on every iteration.
+
+typedef __INTPTR_TYPE__ intptr_t;
+
+template <typename PointerTy>
+struct SmarterPointer {
+ PointerTy getFromVoidPointer(void *P) const {
+ return static_cast<PointerTy>(P);
+ }
+
+ PointerTy getPointer() const {
+ return getFromVoidPointer(reinterpret_cast<void *>(Value));
+ }
+
+ intptr_t Value = 13;
+};
+
+struct Node {
+ SmarterPointer<Node *> Pred;
+};
+
+void test(Node *N) {
+ while (N) {
+ SmarterPointer<Node *> Next = N->Pred;
+ delete N;
+
+ N = Next.getPointer();
+ // no-warning: 'Use of memory after it is freed' was here as the same
+ // 'StackArgumentsSpaceRegion' purged out twice as 'P'.
+ }
+}