r363891 - [analyzer] RetainCount: Add support for OSRequiredCast().

Artem Dergachev via cfe-commits cfe-commits at lists.llvm.org
Wed Jun 19 16:33:34 PDT 2019


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 at -1{{TRUE}}
+                                    // expected-note at -2{{Assuming 'arr1' is not equal to 'obj'}}
+                                    // expected-warning at -3{{FALSE}}
+                                    // expected-note at -4   {{FALSE}}
+  OSArray *arr2 = OSRequiredCast(OSArray, obj);
+  clang_analyzer_eval(arr2 == obj); // expected-warning{{TRUE}}
+                                    // expected-note at -1{{TRUE}}
+}
+
 unsigned int check_dynamic_cast_no_null_on_orig(OSObject *obj) {
   OSArray *arr = OSDynamicCast(OSArray, obj);
   if (arr) {




More information about the cfe-commits mailing list