Author: george.karpenkov Date: Thu Oct 11 15:59:16 2018 New Revision: 344311
URL: http://llvm.org/viewvc/llvm-project?rev=344311&view=rev Log: [analyzer] Retain count checker for OSObject: recognize OSDynamicCast For now, tresting the cast as a no-op, and disregarding the case where the output becomes null due to the type mismatch. rdar://45174557 Differential Revision: https://reviews.llvm.org/D53156 Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp cfe/trunk/test/Analysis/osobject-retain-release.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp?rev=344311&r1=344310&r2=344311&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp Thu Oct 11 15:59:16 2018 @@ -774,12 +774,23 @@ bool RetainCountChecker::evalCall(const // annotate attribute. If it does, we will not inline it. bool hasTrustedImplementationAnnotation = false; + const LocationContext *LCtx = C.getLocationContext(); + + // Process OSDynamicCast: should just return the first argument. + // For now, tresting the cast as a no-op, and disregarding the case where + // the output becomes null due to the type mismatch. + if (FD->getNameAsString() == "safeMetaCast") { + state = state->BindExpr(CE, LCtx, + state->getSVal(CE->getArg(0), LCtx)); + C.addTransition(state); + return true; + } + // See if it's one of the specific functions we know how to eval. if (!SmrMgr.canEval(CE, FD, hasTrustedImplementationAnnotation)) return false; // Bind the return value. - const LocationContext *LCtx = C.getLocationContext(); SVal RetVal = state->getSVal(CE->getArg(0), LCtx); if (RetVal.isUnknown() || (hasTrustedImplementationAnnotation && !ResultTy.isNull())) { Modified: cfe/trunk/test/Analysis/osobject-retain-release.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/osobject-retain-release.cpp?rev=344311&r1=344310&r2=344311&view=diff ============================================================================== --- cfe/trunk/test/Analysis/osobject-retain-release.cpp (original) +++ cfe/trunk/test/Analysis/osobject-retain-release.cpp Thu Oct 11 15:59:16 2018 @@ -1,18 +1,46 @@ // RUN: %clang_analyze_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-config osx.cocoa.RetainCount:CheckOSObject=true -analyzer-output=text -verify %s +struct OSMetaClass; + +#define OSTypeID(type) (type::metaClass) + +#define OSDynamicCast(type, inst) \ + ((type *) OSMetaClassBase::safeMetaCast((inst), OSTypeID(type))) + struct OSObject { virtual void retain(); virtual void release(); - virtual ~OSObject(){} + + static OSObject *generateObject(int); + + static const OSMetaClass * const metaClass; }; struct OSArray : public OSObject { unsigned int getCount(); static OSArray *withCapacity(unsigned int capacity); + + static const OSMetaClass * const metaClass; +}; + +struct OSMetaClassBase { + static OSObject *safeMetaCast(const OSObject *inst, const OSMetaClass *meta); }; +void check_dynamic_cast() { + OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1)); + arr->release(); +} + +void check_dynamic_cast_null_check() { + OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1)); + if (!arr) + return; + arr->release(); +} + void use_after_release() { OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}} arr->release(); // expected-note{{Object released}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits