Index: clang/include/clang/StaticAnalyzer/Core/RetainSummaryManager.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/RetainSummaryManager.h +++ clang/include/clang/StaticAnalyzer/Core/RetainSummaryManager.h @@ -139,7 +139,7 @@ OwnedWhenTrackedReceiver, // Treat this function as returning a non-tracked symbol even if // the function has been inlined. This is used where the call - // site summary is more presise than the summary indirectly produced + // site summary is more precise than the summary indirectly produced // by inlining the function NoRetHard }; Index: clang/lib/StaticAnalyzer/Core/RetainSummaryManager.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/RetainSummaryManager.cpp +++ clang/lib/StaticAnalyzer/Core/RetainSummaryManager.cpp @@ -65,6 +65,10 @@ return isSubclass(D, "OSObject"); } +static bool isOSObjectDynamicCast(StringRef S) { + return S == "safeMetaCast"; +} + static bool hasRCAnnotation(const Decl *D, StringRef rcAnnotation) { for (const auto *Ann : D->specific_attrs()) { if (Ann->getAnnotation() == rcAnnotation) @@ -227,6 +231,9 @@ if (TrackOSObjects && PD && isOSObjectSubclass(PD)) { if (const IdentifierInfo *II = FD->getIdentifier()) { + if (isOSObjectDynamicCast(II->getName())) + return getDefaultSummary(); + // All objects returned with functions starting with "get" are getters. if (II->getName().startswith("get")) { return getOSSummaryGetRule(FD); @@ -471,8 +478,12 @@ Summ = getFunctionSummary(cast(Call).getDecl()); break; case CE_CXXMemberOperator: - case CE_Block: + Summ = getFunctionSummary(cast(Call).getDecl()); + break; case CE_CXXConstructor: + Summ = getFunctionSummary(cast(Call).getDecl()); + break; + case CE_Block: case CE_CXXDestructor: case CE_CXXAllocator: // FIXME: These calls are currently unsupported. @@ -536,7 +547,7 @@ // Process OSDynamicCast: should just return the first argument. // For now, treating the cast as a no-op, and disregarding the case where // the output becomes null due to the type mismatch. - if (TrackOSObjects && FName == "safeMetaCast") { + if (TrackOSObjects && isOSObjectDynamicCast(FName)) { return BehaviorSummary::IdentityNonZero; } Index: clang/test/Analysis/osobject-retain-release.cpp =================================================================== --- clang/test/Analysis/osobject-retain-release.cpp +++ clang/test/Analysis/osobject-retain-release.cpp @@ -43,10 +43,11 @@ struct OtherStruct { static void doNothingToArray(OSArray *array); + OtherStruct(OSArray *arr); }; struct OSMetaClassBase { - static OS_RETURNS_NOT_RETAINED OSObject *safeMetaCast(const OSObject *inst, const OSMetaClass *meta); + static OSObject *safeMetaCast(const OSObject *inst, const OSMetaClass *meta); }; void check_no_invalidation() { @@ -55,6 +56,12 @@ } // expected-warning{{Potential leak of an object stored into 'arr'}} // expected-note@-1{{Object leaked}} +void check_no_invalidation_other_struct() { + OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}} + OtherStruct other(arr); // expected-warning{{Potential leak}} + // expected-note@-1{{Object leaked}} +} + void check_rc_consumed() { OSArray *arr = OSArray::withCapacity(10); OSArray::consumeArray(arr);