summaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Checkers
diff options
context:
space:
mode:
Diffstat (limited to 'lib/StaticAnalyzer/Checkers')
-rw-r--r--lib/StaticAnalyzer/Checkers/CStringChecker.cpp1
-rw-r--r--lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp188
-rw-r--r--lib/StaticAnalyzer/Checkers/IteratorChecker.cpp25
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocChecker.cpp43
-rw-r--r--lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/RunLoopAutoreleaseLeakChecker.cpp18
-rw-r--r--lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp10
7 files changed, 194 insertions, 93 deletions
diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index 278452ec994a6..12a576e5d80d5 100644
--- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -552,6 +552,7 @@ void CStringChecker::emitNullArgBug(CheckerContext &C, ProgramStateRef State,
BuiltinBug *BT = static_cast<BuiltinBug *>(BT_Null.get());
auto Report = llvm::make_unique<BugReport>(*BT, WarningMsg, N);
+ Report->addRange(S->getSourceRange());
bugreporter::trackNullOrUndefValue(N, S, *Report);
C.emitReport(std::move(Report));
}
diff --git a/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp b/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp
index ed877ab345189..29677f737f5cf 100644
--- a/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp
@@ -91,37 +91,53 @@ public:
ReserveFn("reserve"), ResizeFn("resize"),
ShrinkToFitFn("shrink_to_fit"), SwapFn("swap") {}
- /// Check whether the function called on the container object is a
- /// member function that potentially invalidates pointers referring
- /// to the objects's internal buffer.
- bool mayInvalidateBuffer(const CallEvent &Call) const;
-
- /// Record the connection between the symbol returned by c_str() and the
- /// corresponding string object region in the ProgramState. Mark the symbol
- /// released if the string object is destroyed.
+ /// Check if the object of this member function call is a `basic_string`.
+ bool isCalledOnStringObject(const CXXInstanceCall *ICall) const;
+
+ /// Check whether the called member function potentially invalidates
+ /// pointers referring to the container object's inner buffer.
+ bool isInvalidatingMemberFunction(const CallEvent &Call) const;
+
+ /// Mark pointer symbols associated with the given memory region released
+ /// in the program state.
+ void markPtrSymbolsReleased(const CallEvent &Call, ProgramStateRef State,
+ const MemRegion *ObjRegion,
+ CheckerContext &C) const;
+
+ /// Standard library functions that take a non-const `basic_string` argument by
+ /// reference may invalidate its inner pointers. Check for these cases and
+ /// mark the pointers released.
+ void checkFunctionArguments(const CallEvent &Call, ProgramStateRef State,
+ CheckerContext &C) const;
+
+ /// Record the connection between raw pointers referring to a container
+ /// object's inner buffer and the object's memory region in the program state.
+ /// Mark potentially invalidated pointers released.
void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
- /// Clean up the ProgramState map.
+ /// Clean up the program state map.
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
};
} // end anonymous namespace
-// [string.require]
-//
-// "References, pointers, and iterators referring to the elements of a
-// basic_string sequence may be invalidated by the following uses of that
-// basic_string object:
-//
-// -- TODO: As an argument to any standard library function taking a reference
-// to non-const basic_string as an argument. For example, as an argument to
-// non-member functions swap(), operator>>(), and getline(), or as an argument
-// to basic_string::swap().
-//
-// -- Calling non-const member functions, except operator[], at, front, back,
-// begin, rbegin, end, and rend."
-//
-bool InnerPointerChecker::mayInvalidateBuffer(const CallEvent &Call) const {
+bool InnerPointerChecker::isCalledOnStringObject(
+ const CXXInstanceCall *ICall) const {
+ const auto *ObjRegion =
+ dyn_cast_or_null<TypedValueRegion>(ICall->getCXXThisVal().getAsRegion());
+ if (!ObjRegion)
+ return false;
+
+ QualType ObjTy = ObjRegion->getValueType();
+ if (ObjTy.isNull() ||
+ ObjTy->getAsCXXRecordDecl()->getName() != "basic_string")
+ return false;
+
+ return true;
+}
+
+bool InnerPointerChecker::isInvalidatingMemberFunction(
+ const CallEvent &Call) const {
if (const auto *MemOpCall = dyn_cast<CXXMemberOperatorCall>(&Call)) {
OverloadedOperatorKind Opc = MemOpCall->getOriginExpr()->getOperator();
if (Opc == OO_Equal || Opc == OO_PlusEqual)
@@ -137,53 +153,104 @@ bool InnerPointerChecker::mayInvalidateBuffer(const CallEvent &Call) const {
Call.isCalled(SwapFn));
}
-void InnerPointerChecker::checkPostCall(const CallEvent &Call,
- CheckerContext &C) const {
- const auto *ICall = dyn_cast<CXXInstanceCall>(&Call);
- if (!ICall)
+void InnerPointerChecker::markPtrSymbolsReleased(const CallEvent &Call,
+ ProgramStateRef State,
+ const MemRegion *MR,
+ CheckerContext &C) const {
+ if (const PtrSet *PS = State->get<RawPtrMap>(MR)) {
+ const Expr *Origin = Call.getOriginExpr();
+ for (const auto Symbol : *PS) {
+ // NOTE: `Origin` may be null, and will be stored so in the symbol's
+ // `RefState` in MallocChecker's `RegionState` program state map.
+ State = allocation_state::markReleased(State, Symbol, Origin);
+ }
+ State = State->remove<RawPtrMap>(MR);
+ C.addTransition(State);
return;
+ }
+}
- SVal Obj = ICall->getCXXThisVal();
- const auto *ObjRegion = dyn_cast_or_null<TypedValueRegion>(Obj.getAsRegion());
- if (!ObjRegion)
- return;
+void InnerPointerChecker::checkFunctionArguments(const CallEvent &Call,
+ ProgramStateRef State,
+ CheckerContext &C) const {
+ if (const auto *FC = dyn_cast<AnyFunctionCall>(&Call)) {
+ const FunctionDecl *FD = FC->getDecl();
+ if (!FD || !FD->isInStdNamespace())
+ return;
- auto *TypeDecl = ObjRegion->getValueType()->getAsCXXRecordDecl();
- if (TypeDecl->getName() != "basic_string")
- return;
+ for (unsigned I = 0, E = FD->getNumParams(); I != E; ++I) {
+ QualType ParamTy = FD->getParamDecl(I)->getType();
+ if (!ParamTy->isReferenceType() ||
+ ParamTy->getPointeeType().isConstQualified())
+ continue;
- ProgramStateRef State = C.getState();
+ // In case of member operator calls, `this` is counted as an
+ // argument but not as a parameter.
+ bool isaMemberOpCall = isa<CXXMemberOperatorCall>(FC);
+ unsigned ArgI = isaMemberOpCall ? I+1 : I;
- if (Call.isCalled(CStrFn) || Call.isCalled(DataFn)) {
- SVal RawPtr = Call.getReturnValue();
- if (SymbolRef Sym = RawPtr.getAsSymbol(/*IncludeBaseRegions=*/true)) {
- // Start tracking this raw pointer by adding it to the set of symbols
- // associated with this container object in the program state map.
- PtrSet::Factory &F = State->getStateManager().get_context<PtrSet>();
- const PtrSet *SetPtr = State->get<RawPtrMap>(ObjRegion);
- PtrSet Set = SetPtr ? *SetPtr : F.getEmptySet();
- assert(C.wasInlined || !Set.contains(Sym));
- Set = F.add(Set, Sym);
- State = State->set<RawPtrMap>(ObjRegion, Set);
- C.addTransition(State);
+ SVal Arg = FC->getArgSVal(ArgI);
+ const auto *ArgRegion =
+ dyn_cast_or_null<TypedValueRegion>(Arg.getAsRegion());
+ if (!ArgRegion)
+ continue;
+
+ markPtrSymbolsReleased(Call, State, ArgRegion, C);
}
- return;
}
+}
- if (mayInvalidateBuffer(Call)) {
- if (const PtrSet *PS = State->get<RawPtrMap>(ObjRegion)) {
- // Mark all pointer symbols associated with the deleted object released.
- const Expr *Origin = Call.getOriginExpr();
- for (const auto Symbol : *PS) {
- // NOTE: `Origin` may be null, and will be stored so in the symbol's
- // `RefState` in MallocChecker's `RegionState` program state map.
- State = allocation_state::markReleased(State, Symbol, Origin);
+// [string.require]
+//
+// "References, pointers, and iterators referring to the elements of a
+// basic_string sequence may be invalidated by the following uses of that
+// basic_string object:
+//
+// -- As an argument to any standard library function taking a reference
+// to non-const basic_string as an argument. For example, as an argument to
+// non-member functions swap(), operator>>(), and getline(), or as an argument
+// to basic_string::swap().
+//
+// -- Calling non-const member functions, except operator[], at, front, back,
+// begin, rbegin, end, and rend."
+
+void InnerPointerChecker::checkPostCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+
+ if (const auto *ICall = dyn_cast<CXXInstanceCall>(&Call)) {
+ if (isCalledOnStringObject(ICall)) {
+ const auto *ObjRegion = dyn_cast_or_null<TypedValueRegion>(
+ ICall->getCXXThisVal().getAsRegion());
+
+ if (Call.isCalled(CStrFn) || Call.isCalled(DataFn)) {
+ SVal RawPtr = Call.getReturnValue();
+ if (SymbolRef Sym = RawPtr.getAsSymbol(/*IncludeBaseRegions=*/true)) {
+ // Start tracking this raw pointer by adding it to the set of symbols
+ // associated with this container object in the program state map.
+
+ PtrSet::Factory &F = State->getStateManager().get_context<PtrSet>();
+ const PtrSet *SetPtr = State->get<RawPtrMap>(ObjRegion);
+ PtrSet Set = SetPtr ? *SetPtr : F.getEmptySet();
+ assert(C.wasInlined || !Set.contains(Sym));
+ Set = F.add(Set, Sym);
+
+ State = State->set<RawPtrMap>(ObjRegion, Set);
+ C.addTransition(State);
+ }
+ return;
+ }
+
+ // Check [string.require] / second point.
+ if (isInvalidatingMemberFunction(Call)) {
+ markPtrSymbolsReleased(Call, State, ObjRegion, C);
+ return;
}
- State = State->remove<RawPtrMap>(ObjRegion);
- C.addTransition(State);
- return;
}
}
+
+ // Check [string.require] / first point.
+ checkFunctionArguments(Call, State, C);
}
void InnerPointerChecker::checkDeadSymbols(SymbolReaper &SymReaper,
@@ -216,7 +283,6 @@ InnerPointerChecker::InnerPointerBRVisitor::VisitNode(const ExplodedNode *N,
const ExplodedNode *PrevN,
BugReporterContext &BRC,
BugReport &BR) {
-
if (!isSymbolTracked(N->getState(), PtrToBuf) ||
isSymbolTracked(PrevN->getState(), PtrToBuf))
return nullptr;
diff --git a/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp b/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp
index 56c250cd16783..520c32e1c7703 100644
--- a/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp
@@ -291,6 +291,7 @@ const ContainerData *getContainerData(ProgramStateRef State,
const MemRegion *Cont);
ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont,
const ContainerData &CData);
+bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont);
bool isOutOfRange(ProgramStateRef State, const IteratorPosition &Pos);
bool isZero(ProgramStateRef State, const NonLoc &Val);
} // namespace
@@ -536,7 +537,11 @@ void IteratorChecker::checkDeadSymbols(SymbolReaper &SR,
auto ContMap = State->get<ContainerMap>();
for (const auto Cont : ContMap) {
if (!SR.isLiveRegion(Cont.first)) {
- State = State->remove<ContainerMap>(Cont.first);
+ // We must keep the container data while it has live iterators to be able
+ // to compare them to the begin and the end of the container.
+ if (!hasLiveIterators(State, Cont.first)) {
+ State = State->remove<ContainerMap>(Cont.first);
+ }
}
}
@@ -546,6 +551,8 @@ void IteratorChecker::checkDeadSymbols(SymbolReaper &SR,
State = State->remove<IteratorComparisonMap>(Comp.first);
}
}
+
+ C.addTransition(State);
}
ProgramStateRef IteratorChecker::evalAssume(ProgramStateRef State, SVal Cond,
@@ -1188,6 +1195,22 @@ ProgramStateRef relateIteratorPositions(ProgramStateRef State,
return NewState;
}
+bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont) {
+ auto RegionMap = State->get<IteratorRegionMap>();
+ for (const auto Reg : RegionMap) {
+ if (Reg.second.getContainer() == Cont)
+ return true;
+ }
+
+ auto SymbolMap = State->get<IteratorSymbolMap>();
+ for (const auto Sym : SymbolMap) {
+ if (Sym.second.getContainer() == Cont)
+ return true;
+ }
+
+ return false;
+}
+
bool isZero(ProgramStateRef State, const NonLoc &Val) {
auto &BVF = State->getBasicVals();
return compare(State, Val,
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 8f07f413e81f6..ebaf79a780c07 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -179,11 +179,11 @@ public:
II_strdup(nullptr), II_win_strdup(nullptr), II_kmalloc(nullptr),
II_if_nameindex(nullptr), II_if_freenameindex(nullptr),
II_wcsdup(nullptr), II_win_wcsdup(nullptr), II_g_malloc(nullptr),
- II_g_malloc0(nullptr), II_g_realloc(nullptr), II_g_try_malloc(nullptr),
- II_g_try_malloc0(nullptr), II_g_try_realloc(nullptr),
- II_g_free(nullptr), II_g_memdup(nullptr), II_g_malloc_n(nullptr),
- II_g_malloc0_n(nullptr), II_g_realloc_n(nullptr),
- II_g_try_malloc_n(nullptr), II_g_try_malloc0_n(nullptr),
+ II_g_malloc0(nullptr), II_g_realloc(nullptr), II_g_try_malloc(nullptr),
+ II_g_try_malloc0(nullptr), II_g_try_realloc(nullptr),
+ II_g_free(nullptr), II_g_memdup(nullptr), II_g_malloc_n(nullptr),
+ II_g_malloc0_n(nullptr), II_g_realloc_n(nullptr),
+ II_g_try_malloc_n(nullptr), II_g_try_malloc0_n(nullptr),
II_g_try_realloc_n(nullptr) {}
/// In pessimistic mode, the checker assumes that it does not know which
@@ -248,11 +248,11 @@ private:
*II_realloc, *II_calloc, *II_valloc, *II_reallocf,
*II_strndup, *II_strdup, *II_win_strdup, *II_kmalloc,
*II_if_nameindex, *II_if_freenameindex, *II_wcsdup,
- *II_win_wcsdup, *II_g_malloc, *II_g_malloc0,
- *II_g_realloc, *II_g_try_malloc, *II_g_try_malloc0,
- *II_g_try_realloc, *II_g_free, *II_g_memdup,
- *II_g_malloc_n, *II_g_malloc0_n, *II_g_realloc_n,
- *II_g_try_malloc_n, *II_g_try_malloc0_n,
+ *II_win_wcsdup, *II_g_malloc, *II_g_malloc0,
+ *II_g_realloc, *II_g_try_malloc, *II_g_try_malloc0,
+ *II_g_try_realloc, *II_g_free, *II_g_memdup,
+ *II_g_malloc_n, *II_g_malloc0_n, *II_g_realloc_n,
+ *II_g_try_malloc_n, *II_g_try_malloc0_n,
*II_g_try_realloc_n;
mutable Optional<uint64_t> KernelZeroFlagVal;
@@ -346,7 +346,7 @@ private:
ProgramStateRef ReallocMemAux(CheckerContext &C, const CallExpr *CE,
bool FreesMemOnFailure,
- ProgramStateRef State,
+ ProgramStateRef State,
bool SuffixWithN = false) const;
static SVal evalMulForBufferSize(CheckerContext &C, const Expr *Blocks,
const Expr *BlockBytes);
@@ -652,7 +652,7 @@ bool MallocChecker::isCMemFunction(const FunctionDecl *FD,
initIdentifierInfo(C);
if (Family == AF_Malloc && CheckFree) {
- if (FunI == II_free || FunI == II_realloc || FunI == II_reallocf ||
+ if (FunI == II_free || FunI == II_realloc || FunI == II_reallocf ||
FunI == II_g_free)
return true;
}
@@ -662,12 +662,12 @@ bool MallocChecker::isCMemFunction(const FunctionDecl *FD,
FunI == II_calloc || FunI == II_valloc || FunI == II_strdup ||
FunI == II_win_strdup || FunI == II_strndup || FunI == II_wcsdup ||
FunI == II_win_wcsdup || FunI == II_kmalloc ||
- FunI == II_g_malloc || FunI == II_g_malloc0 ||
- FunI == II_g_realloc || FunI == II_g_try_malloc ||
+ FunI == II_g_malloc || FunI == II_g_malloc0 ||
+ FunI == II_g_realloc || FunI == II_g_try_malloc ||
FunI == II_g_try_malloc0 || FunI == II_g_try_realloc ||
- FunI == II_g_memdup || FunI == II_g_malloc_n ||
- FunI == II_g_malloc0_n || FunI == II_g_realloc_n ||
- FunI == II_g_try_malloc_n || FunI == II_g_try_malloc0_n ||
+ FunI == II_g_memdup || FunI == II_g_malloc_n ||
+ FunI == II_g_malloc0_n || FunI == II_g_realloc_n ||
+ FunI == II_g_try_malloc_n || FunI == II_g_try_malloc0_n ||
FunI == II_g_try_realloc_n)
return true;
}
@@ -873,7 +873,7 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
return;
State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State);
State = ProcessZeroAllocation(C, CE, 0, State);
- } else if (FunI == II_realloc || FunI == II_g_realloc ||
+ } else if (FunI == II_realloc || FunI == II_g_realloc ||
FunI == II_g_try_realloc) {
State = ReallocMemAux(C, CE, false, State);
State = ProcessZeroAllocation(C, CE, 1, State);
@@ -936,7 +936,7 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
return;
State = MallocMemAux(C, CE, CE->getArg(1), UndefinedVal(), State);
State = ProcessZeroAllocation(C, CE, 1, State);
- } else if (FunI == II_g_malloc_n || FunI == II_g_try_malloc_n ||
+ } else if (FunI == II_g_malloc_n || FunI == II_g_try_malloc_n ||
FunI == II_g_malloc0_n || FunI == II_g_try_malloc0_n) {
if (CE->getNumArgs() < 2)
return;
@@ -2930,6 +2930,11 @@ std::shared_ptr<PathDiagnosticPiece> MallocChecker::MallocBugVisitor::VisitNode(
OS << MemCallE->getMethodDecl()->getNameAsString();
} else if (const auto *OpCallE = dyn_cast<CXXOperatorCallExpr>(S)) {
OS << OpCallE->getDirectCallee()->getNameAsString();
+ } else if (const auto *CallE = dyn_cast<CallExpr>(S)) {
+ auto &CEMgr = BRC.getStateManager().getCallEventManager();
+ CallEventRef<> Call = CEMgr.getSimpleCall(CallE, state, CurrentLC);
+ const auto *D = dyn_cast_or_null<NamedDecl>(Call->getDecl());
+ OS << (D ? D->getNameAsString() : "unknown");
}
OS << "'";
}
diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
index 2c1e139330d68..9c85c09837239 100644
--- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
@@ -4000,7 +4000,7 @@ void RetainCountChecker::checkEndFunction(const ReturnStmt *RS,
// Don't process anything within synthesized bodies.
const LocationContext *LCtx = Pred->getLocationContext();
if (LCtx->getAnalysisDeclContext()->isBodyAutosynthesized()) {
- assert(!LCtx->inTopFrame());
+ assert(!LCtx->inTopFrame());
return;
}
diff --git a/lib/StaticAnalyzer/Checkers/RunLoopAutoreleaseLeakChecker.cpp b/lib/StaticAnalyzer/Checkers/RunLoopAutoreleaseLeakChecker.cpp
index 64b61a0213d28..55516a34d1a78 100644
--- a/lib/StaticAnalyzer/Checkers/RunLoopAutoreleaseLeakChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/RunLoopAutoreleaseLeakChecker.cpp
@@ -45,9 +45,9 @@ const char * RunLoopBind = "NSRunLoopM";
const char * RunLoopRunBind = "RunLoopRunM";
const char * OtherMsgBind = "OtherMessageSentM";
const char * AutoreleasePoolBind = "AutoreleasePoolM";
+const char * OtherStmtAutoreleasePoolBind = "OtherAutoreleasePoolM";
-class RunLoopAutoreleaseLeakChecker : public Checker<
- check::ASTCodeBody> {
+class RunLoopAutoreleaseLeakChecker : public Checker<check::ASTCodeBody> {
public:
void checkASTCodeBody(const Decl *D,
@@ -66,6 +66,8 @@ static TriBoolTy
seenBeforeRec(const Stmt *Parent, const Stmt *A, const Stmt *B,
MemoizationMapTy &Memoization) {
for (const Stmt *C : Parent->children()) {
+ if (!C) continue;
+
if (C == A)
return true;
@@ -110,17 +112,20 @@ static void emitDiagnostics(BoundNodes &Match,
const auto *AP =
Match.getNodeAs<ObjCAutoreleasePoolStmt>(AutoreleasePoolBind);
+ const auto *OAP =
+ Match.getNodeAs<ObjCAutoreleasePoolStmt>(OtherStmtAutoreleasePoolBind);
bool HasAutoreleasePool = (AP != nullptr);
const auto *RL = Match.getNodeAs<ObjCMessageExpr>(RunLoopBind);
const auto *RLR = Match.getNodeAs<Stmt>(RunLoopRunBind);
assert(RLR && "Run loop launch not found");
-
assert(ME != RLR);
- if (HasAutoreleasePool && seenBefore(AP, RLR, ME))
+
+ // Launch of run loop occurs before the message-sent expression is seen.
+ if (seenBefore(DeclBody, RLR, ME))
return;
- if (!HasAutoreleasePool && seenBefore(DeclBody, RLR, ME))
+ if (HasAutoreleasePool && (OAP != AP))
return;
PathDiagnosticLocation Location = PathDiagnosticLocation::createBegin(
@@ -169,7 +174,8 @@ static void
checkTempObjectsInSamePool(const Decl *D, AnalysisManager &AM, BugReporter &BR,
const RunLoopAutoreleaseLeakChecker *Chkr) {
StatementMatcher RunLoopRunM = getRunLoopRunM();
- StatementMatcher OtherMessageSentM = getOtherMessageSentM();
+ StatementMatcher OtherMessageSentM = getOtherMessageSentM(
+ hasAncestor(autoreleasePoolStmt().bind(OtherStmtAutoreleasePoolBind)));
StatementMatcher RunLoopInAutorelease =
autoreleasePoolStmt(
diff --git a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index feae9e59b343a..e7a20fa03a4ae 100644
--- a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -129,7 +129,7 @@ bool StackAddrEscapeChecker::isSemaphoreCaptured(const BlockDecl &B) const {
for (const auto &C : B.captures()) {
const auto *T = C.getVariable()->getType()->getAs<TypedefType>();
if (T && T->getDecl()->getIdentifier() == dispatch_semaphore_tII)
- return true;
+ return true;
}
return false;
}
@@ -175,9 +175,9 @@ void StackAddrEscapeChecker::checkAsyncExecutedBlockCaptures(
// There is a not-too-uncommon idiom
// where a block passed to dispatch_async captures a semaphore
// and then the thread (which called dispatch_async) is blocked on waiting
- // for the completion of the execution of the block
- // via dispatch_semaphore_wait. To avoid false-positives (for now)
- // we ignore all the blocks which have captured
+ // for the completion of the execution of the block
+ // via dispatch_semaphore_wait. To avoid false-positives (for now)
+ // we ignore all the blocks which have captured
// a variable of the type "dispatch_semaphore_t".
if (isSemaphoreCaptured(*B.getDecl()))
return;
@@ -263,7 +263,7 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
if (const BlockDataRegion *B = dyn_cast<BlockDataRegion>(R))
checkReturnedBlockCaptures(*B, C);
- if (!isa<StackSpaceRegion>(R->getMemorySpace()) ||
+ if (!isa<StackSpaceRegion>(R->getMemorySpace()) ||
isNotInCurrentFrame(R, C) || isArcManagedBlock(R, C))
return;