]> granicus.if.org Git - clang/commitdiff
[analyzer] Retain count checker for OSObject: recognize OSDynamicCast
authorGeorge Karpenkov <ekarpenkov@apple.com>
Thu, 11 Oct 2018 22:59:16 +0000 (22:59 +0000)
committerGeorge Karpenkov <ekarpenkov@apple.com>
Thu, 11 Oct 2018 22:59:16 +0000 (22:59 +0000)
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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@344311 91177308-0d34-0410-b5e6-96231b3b80d8

lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
test/Analysis/osobject-retain-release.cpp

index e5d27f577d11ca0889ec6741665ede46d08ee154..ca58f14985ccbd441bda9828d8b1c528bf1fc49d 100644 (file)
@@ -774,12 +774,23 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) 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())) {
index 18bdf0bafc55b5cc69bad72923f9f78648726129..c1b93fce50f9f94ad92406886f717dcf65de9fee 100644 (file)
@@ -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}}