Index: clang/lib/StaticAnalyzer/Core/RetainSummaryManager.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/RetainSummaryManager.cpp +++ clang/lib/StaticAnalyzer/Core/RetainSummaryManager.cpp @@ -94,6 +94,22 @@ return FName.contains_lower("MakeCollectable"); } +/// A function is OSObject related if it is declared on a subclass +/// of OSObject, or any of the parameters is a subclass of an OSObject. +static bool isOSObjectRelated(const CXXMethodDecl *MD) { + if (isOSObjectSubclass(MD->getParent())) + return true; + + for (ParmVarDecl *Param : MD->parameters()) { + if (CXXRecordDecl *RD = Param->getType()->getAsCXXRecordDecl()) { + if (isOSObjectSubclass(RD)) + return true; + } + } + + return false; +} + const RetainSummary * RetainSummaryManager::generateSummary(const FunctionDecl *FD, bool &AllowAnnotations) { @@ -322,12 +338,12 @@ } } - if (isa(FD)) { - - // Stop tracking arguments passed to C++ methods, as those might be - // wrapping smart pointers. - return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, StopTracking, - DoNothing); + if (const auto *MD = dyn_cast(FD)) { + if (!(TrackOSObjects && isOSObjectRelated(MD))) + // Stop tracking arguments passed to C++ methods, as those might be + // wrapping smart pointers, unless the tracking relates to OSObject. + return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, StopTracking, + DoNothing); } return getDefaultSummary(); @@ -642,6 +658,8 @@ if (D->hasAttr()) return RetEffect::MakeNotOwned(RetEffect::CF); + else if (hasRCAnnotation(D, "rc_ownership_returns_not_retained")) + return RetEffect::MakeNotOwned(RetEffect::Generalized); return None; } Index: clang/test/Analysis/osobject-retain-release.cpp =================================================================== --- clang/test/Analysis/osobject-retain-release.cpp +++ clang/test/Analysis/osobject-retain-release.cpp @@ -2,6 +2,11 @@ struct OSMetaClass; +#define TRUSTED __attribute__((annotate("rc_ownership_trusted_implementation"))) +#define OS_CONSUME TRUSTED __attribute__((annotate("rc_ownership_consumed"))) +#define OS_RETURNS_RETAINED TRUSTED __attribute__((annotate("rc_ownership_returns_retained"))) +#define OS_RETURNS_NOT_RETAINED TRUSTED __attribute__((annotate("rc_ownership_returns_not_retained"))) + #define OSTypeID(type) (type::metaClass) #define OSDynamicCast(type, inst) \ @@ -21,6 +26,15 @@ unsigned int getCount(); static OSArray *withCapacity(unsigned int capacity); + static void consumeArray(OS_CONSUME OSArray * array); + + static OSArray* consumeArrayHasCode(OS_CONSUME OSArray * array) { + return nullptr; + } + + static OS_RETURNS_NOT_RETAINED OSArray *MaskedGetter(); + static OS_RETURNS_RETAINED OSArray *getOoopsActuallyCreate(); + static const OSMetaClass * const metaClass; }; @@ -29,6 +43,26 @@ static OSObject *safeMetaCast(const OSObject *inst, const OSMetaClass *meta); }; +void check_rc_consumed() { + OSArray *arr = OSArray::withCapacity(10); + OSArray::consumeArray(arr); +} + +void check_rc_consume_temporary() { + OSArray::consumeArray(OSArray::withCapacity(10)); +} + +void check_rc_getter() { + OSArray *arr = OSArray::MaskedGetter(); + (void)arr; +} + +void check_rc_create() { + OSArray *arr = OSArray::getOoopsActuallyCreate(); + arr->release(); +} + + void check_dynamic_cast() { OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1)); arr->release();