From: George Karpenkov Date: Fri, 21 Dec 2018 02:16:36 +0000 (+0000) Subject: [analyzer] Perform escaping in RetainCountChecker on type mismatch even for inlined... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4e2a388a999e41a12743314deb9e0f060252a621;p=clang [analyzer] Perform escaping in RetainCountChecker on type mismatch even for inlined functions The fix done in D55465 did not previously apply when the function was inlined. rdar://46889541 Differential Revision: https://reviews.llvm.org/D55976 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@349876 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp index 488cf6d3eb..87c1ad9edb 100644 --- a/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp @@ -502,6 +502,25 @@ static Optional refValFromRetEffect(RetEffect RE, return None; } +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()); +} + // We don't always get the exact modeling of the function with regards to the // retain count checker even when the function is inlined. For example, we need // to stop tracking the symbols which were marked with StopTrackingHard. @@ -512,11 +531,16 @@ void RetainCountChecker::processSummaryOfInlined(const RetainSummary &Summ, // Evaluate the effect of the arguments. for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) { - if (Summ.getArg(idx) == StopTrackingHard) { - SVal V = CallOrMsg.getArgSVal(idx); - if (SymbolRef Sym = V.getAsLocSymbol()) { + SVal V = CallOrMsg.getArgSVal(idx); + + if (SymbolRef Sym = V.getAsLocSymbol()) { + bool ShouldRemoveBinding = Summ.getArg(idx) == StopTrackingHard; + if (const RefVal *T = getRefBinding(state, Sym)) + if (shouldEscapeArgumentOnCall(CallOrMsg, idx, T)) + ShouldRemoveBinding = true; + + if (ShouldRemoveBinding) state = removeRefBinding(state, Sym); - } } } @@ -574,25 +598,6 @@ 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 { diff --git a/test/Analysis/osobject-retain-release.cpp b/test/Analysis/osobject-retain-release.cpp index 2efd20709b..0cd9deff0e 100644 --- a/test/Analysis/osobject-retain-release.cpp +++ b/test/Analysis/osobject-retain-release.cpp @@ -90,7 +90,10 @@ struct OSMetaClassBase { static OSObject *safeMetaCast(const OSObject *inst, const OSMetaClass *meta); }; +typedef unsigned long MYTYPE; + void escape(void *); +void escape_with_source(MYTYPE p) {} bool coin(); bool os_consume_violation_two_args(OS_CONSUME OSObject *obj, bool extra) { @@ -139,6 +142,13 @@ void test_escaping_into_voidstar() { escape(obj); } +void test_escape_has_source() { + OSObject *obj = new OSObject; + if (obj) + escape_with_source((MYTYPE)obj); + return; +} + void test_no_infinite_check_recursion(MyArray *arr) { OSObject *input = new OSObject; OSObject *o = arr->generateObject(input);