From 041c9fa8bac0374b4099467a3bbbf0222b481693 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Sat, 8 Dec 2018 01:18:40 +0000 Subject: [PATCH] Stop tracking retain count of OSObject after escape to void * / other primitive types Escaping to void * / uint64_t / others non-OSObject * should stop tracking, as such functions can have heterogeneous semantics depending on context, and can not always be annotated. rdar://46439133 Differential Revision: https://reviews.llvm.org/D55465 llvm-svn: 348675 --- .../RetainCountChecker/RetainCountChecker.cpp | 23 +++++++++++++++++++ .../test/Analysis/osobject-retain-release.cpp | 7 ++++++ 2 files changed, 30 insertions(+) diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp index 02c482e6196f1..8d0d407eab83d 100644 --- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp @@ -574,6 +574,25 @@ static ProgramStateRef updateOutParameter(ProgramStateRef State, return State; } +static bool isPointerToObject(QualType QT) { + QualType PT = QT->getPointeeType(); + if (!PT.isNull()) + if (PT->getAsCXXRecordDecl()) + return true; + return false; +} + +/// Whether the tracked value should be escaped on a given call. +/// OSObjects are escaped when passed to void * / etc. +static bool shouldEscapeArgumentOnCall(const CallEvent &CE, unsigned ArgIdx, + const RefVal *TrackedValue) { + if (TrackedValue->getObjKind() != RetEffect::OS) + return false; + if (ArgIdx >= CE.parameters().size()) + return false; + return !isPointerToObject(CE.parameters()[ArgIdx]->getType()); +} + void RetainCountChecker::checkSummary(const RetainSummary &Summ, const CallEvent &CallOrMsg, CheckerContext &C) const { @@ -592,6 +611,10 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ, state = updateOutParameter(state, V, Effect); } else if (SymbolRef Sym = V.getAsLocSymbol()) { if (const RefVal *T = getRefBinding(state, Sym)) { + + if (shouldEscapeArgumentOnCall(CallOrMsg, idx, T)) + Effect = StopTrackingHard; + state = updateSymbol(state, Sym, *T, Effect, hasErr, C); if (hasErr) { ErrorRange = CallOrMsg.getArgSourceRange(idx); diff --git a/clang/test/Analysis/osobject-retain-release.cpp b/clang/test/Analysis/osobject-retain-release.cpp index 9c8bd78726a42..68529e9e972c0 100644 --- a/clang/test/Analysis/osobject-retain-release.cpp +++ b/clang/test/Analysis/osobject-retain-release.cpp @@ -89,6 +89,13 @@ struct OSMetaClassBase { static OSObject *safeMetaCast(const OSObject *inst, const OSMetaClass *meta); }; +void escape(void *); + +void test_escaping_into_voidstar() { + OSObject *obj = new OSObject; + escape(obj); +} + void test_no_infinite_check_recursion(MyArray *arr) { OSObject *input = new OSObject; OSObject *o = arr->generateObject(input);