Index: clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp @@ -574,6 +574,14 @@ return State; } +static bool isPointerToObject(QualType QT) { + QualType PT = QT->getPointeeType(); + if (!PT.isNull()) + if (PT->getAsCXXRecordDecl()) + return true; + return false; +} + void RetainCountChecker::checkSummary(const RetainSummary &Summ, const CallEvent &CallOrMsg, CheckerContext &C) const { @@ -586,13 +594,21 @@ for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) { SVal V = CallOrMsg.getArgSVal(idx); + ParmVarDecl *PD = CallOrMsg.parameters()[idx]; ArgEffect Effect = Summ.getArg(idx); if (Effect == RetainedOutParameter || Effect == UnretainedOutParameter) { state = updateOutParameter(state, V, Effect); } else if (SymbolRef Sym = V.getAsLocSymbol()) { if (const RefVal *T = getRefBinding(state, Sym)) { + + // Escape OSObjects being passed to void * / etc. + if (T->getObjKind() == RetEffect::OS && + !isPointerToObject(PD->getType())) + Effect = StopTrackingHard; + state = updateSymbol(state, Sym, *T, Effect, hasErr, C); + if (hasErr) { ErrorRange = CallOrMsg.getArgSourceRange(idx); ErrorSym = Sym; Index: clang/test/Analysis/osobject-retain-release.cpp =================================================================== --- clang/test/Analysis/osobject-retain-release.cpp +++ clang/test/Analysis/osobject-retain-release.cpp @@ -89,6 +89,13 @@ 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);