Author: dergachev Date: Wed Jun 19 16:33:34 2019 New Revision: 363891 URL: http://llvm.org/viewvc/llvm-project?rev=363891&view=rev Log: [analyzer] RetainCount: Add support for OSRequiredCast().
It's a new API for custom RTTI in Apple IOKit/DriverKit framework that is similar to OSDynamicCast() that's already supported, but crashes instead of returning null (and therefore causing UB when the cast fails unexpectedly). Kind of like cast_or_null<> as opposed to dyn_cast_or_null<> in LLVM's RTTI. Historically, RetainCountChecker was responsible for modeling OSDynamicCast. This is simply an extension of the same functionality. Differential Revision: https://reviews.llvm.org/D63117 Modified: cfe/trunk/lib/Analysis/RetainSummaryManager.cpp cfe/trunk/test/Analysis/os_object_base.h cfe/trunk/test/Analysis/osobject-retain-release.cpp Modified: cfe/trunk/lib/Analysis/RetainSummaryManager.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/RetainSummaryManager.cpp?rev=363891&r1=363890&r2=363891&view=diff ============================================================================== --- cfe/trunk/lib/Analysis/RetainSummaryManager.cpp (original) +++ cfe/trunk/lib/Analysis/RetainSummaryManager.cpp Wed Jun 19 16:33:34 2019 @@ -152,6 +152,10 @@ static bool isOSObjectDynamicCast(String return S == "safeMetaCast"; } +static bool isOSObjectRequiredCast(StringRef S) { + return S == "requiredMetaCast"; +} + static bool isOSObjectThisCast(StringRef S) { return S == "metaCast"; } @@ -234,7 +238,8 @@ RetainSummaryManager::getSummaryForOSObj if (RetTy->isPointerType()) { const CXXRecordDecl *PD = RetTy->getPointeeType()->getAsCXXRecordDecl(); if (PD && isOSObjectSubclass(PD)) { - if (isOSObjectDynamicCast(FName) || isOSObjectThisCast(FName)) + if (isOSObjectDynamicCast(FName) || isOSObjectRequiredCast(FName) || + isOSObjectThisCast(FName)) return getDefaultSummary(); // TODO: Add support for the slightly common *Matching(table) idiom. @@ -745,6 +750,8 @@ RetainSummaryManager::canEval(const Call if (TrackOSObjects) { if (isOSObjectDynamicCast(FName) && FD->param_size() >= 1) { return BehaviorSummary::IdentityOrZero; + } else if (isOSObjectRequiredCast(FName) && FD->param_size() >= 1) { + return BehaviorSummary::Identity; } else if (isOSObjectThisCast(FName) && isa<CXXMethodDecl>(FD) && !cast<CXXMethodDecl>(FD)->isStatic()) { return BehaviorSummary::IdentityThis; Modified: cfe/trunk/test/Analysis/os_object_base.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/os_object_base.h?rev=363891&r1=363890&r2=363891&view=diff ============================================================================== --- cfe/trunk/test/Analysis/os_object_base.h (original) +++ cfe/trunk/test/Analysis/os_object_base.h Wed Jun 19 16:33:34 2019 @@ -12,6 +12,8 @@ #define OSDynamicCast(type, inst) \ ((type *) OSMetaClassBase::safeMetaCast((inst), OSTypeID(type))) +#define OSRequiredCast(type, inst) \ + ((type *) OSMetaClassBase::requiredMetaCast((inst), OSTypeID(type))) #define OSTypeAlloc(type) ((type *) ((type::metaClass)->alloc())) @@ -22,6 +24,8 @@ struct OSMetaClass; struct OSMetaClassBase { static OSMetaClassBase *safeMetaCast(const OSMetaClassBase *inst, const OSMetaClass *meta); + static OSMetaClassBase *requiredMetaCast(const OSMetaClassBase *inst, + const OSMetaClass *meta); OSMetaClassBase *metaCast(const char *toMeta); 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=363891&r1=363890&r2=363891&view=diff ============================================================================== --- cfe/trunk/test/Analysis/osobject-retain-release.cpp (original) +++ cfe/trunk/test/Analysis/osobject-retain-release.cpp Wed Jun 19 16:33:34 2019 @@ -1,9 +1,11 @@ // RUN: %clang_analyze_cc1 -fblocks -analyze -analyzer-output=text\ -// RUN: -analyzer-checker=core,osx -verify %s +// RUN: -analyzer-checker=core,osx,debug.ExprInspection -verify %s #include "os_object_base.h" #include "os_smart_ptr.h" +void clang_analyzer_eval(bool); + struct OSIterator : public OSObject { static const OSMetaClass * const metaClass; }; @@ -483,6 +485,23 @@ void check_dynamic_cast() { arr->release(); } +void check_required_cast() { + OSArray *arr = OSRequiredCast(OSArray, OSObject::generateObject(1)); + arr->release(); // no-warning +} + +void check_cast_behavior(OSObject *obj) { + OSArray *arr1 = OSDynamicCast(OSArray, obj); + clang_analyzer_eval(arr1 == obj); // expected-warning{{TRUE}} + // expected-note@-1{{TRUE}} + // expected-note@-2{{Assuming 'arr1' is not equal to 'obj'}} + // expected-warning@-3{{FALSE}} + // expected-note@-4 {{FALSE}} + OSArray *arr2 = OSRequiredCast(OSArray, obj); + clang_analyzer_eval(arr2 == obj); // expected-warning{{TRUE}} + // expected-note@-1{{TRUE}} +} + unsigned int check_dynamic_cast_no_null_on_orig(OSObject *obj) { OSArray *arr = OSDynamicCast(OSArray, obj); if (arr) { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits