Skip to content

Commit

Permalink
[analyzer] Retain count checker for OSObject: recognize OSDynamicCast
Browse files Browse the repository at this point in the history
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

llvm-svn: 344311
  • Loading branch information
George Karpenkov committed Oct 11, 2018
1 parent 4733be6 commit 41dc8de
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 2 deletions.
Expand Up @@ -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())) {
Expand Down
30 changes: 29 additions & 1 deletion clang/test/Analysis/osobject-retain-release.cpp
@@ -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}}
Expand Down

0 comments on commit 41dc8de

Please sign in to comment.