[cfe-commits] r66712 - in /cfe/trunk: include/clang/Analysis/PathSensitive/MemRegion.h lib/Analysis/MemRegion.cpp

Ted Kremenek kremenek at apple.com
Wed Mar 11 21:14:09 PDT 2009


On Mar 11, 2009, at 7:05 PM, Zhongxing Xu wrote:

>
> This is because 'isBoundable()' is defined in TypedRegion (the  
> parent class) in
> terms of the rvalue type (which could be null),
>
> Hi Ted, I am curious when the rvalue type could be null? Could you  
> please provide a test case caused to crash by my previous patch?

It's strictly an Objective-C issue.  I'll look into providing a small  
test case for the test suite.

Quick lesson: all Objective-C classes are heap allocated.  Like C++,  
you can have pointers to objects, e.g:

   NSObject *myObject

Objective-C also has another pointer-like type called 'id' and  
'id<...>'.  The type 'id' has been around since the early days of the  
language, and is really just a typedef for a pointer to a struct:

   typedef struct objc_object *id;

This type is defined implicitly (see ASTContext::setObjCIdType).  'id'  
is basically a form of void* for Objective-C; it can point an object  
of any Objective-C class.

Recently, "protocols" where introduced into Objective-C.  Protocols  
are similar to "interfaces" in Java.  A class that implements a  
protocol essentially must provide implementations for the methods  
specified in that protocol (just like Java interfaces). This allows us  
to have qualified pointers:

   NSObject<MyProtocol> *myObject;

This means that 'myObject' points to an object that subclasses  
NSObject and also implements the protocol 'MyProtocol'.  In Clang such  
pointers are represented by the type  
"PointerType(ObjCQualifiedInterfaceType)."

Similarly, we have id<...>:

    id<MyProtocol> myObject;

This is a pointer-like reference (represented as the Clang type  
ObjCQualifiedIdType) to any Objective-C object that implements the  
'MyProtocol' protocol.  You should think of it as a pointer.

The problem is that id<..> cannot be treated like a normal pointer.   
Specifically, it cannot be dereferenced.  Consider the following  
Objective-C code:

#include <Foundation/Foundation.h>

void f1(NSObject *x, NSObject *y) {
   *x = *y;
}

void f2(id w, NSObject *z) {
   *w = *z;
}

@protocol MyProtocol;

void f3(id<MyProtocol> p, NSObject<MyProtocol> *q) {
   *p = *q;
}

Here is what clang says:

$ clang /tmp/t.m
/tmp/t.m:8:6: error: incompatible type assigning 'NSObject', expected  
'struct objc_object'
   *w = *z;
      ^ ~~
/tmp/t.m:14:3: error: indirection requires pointer operand  
('id<MyProtocol>' invalid)
   *p = *q;
   ^~
2 diagnostics generated.

Function 'f1' type checks fine.  Function 'f2' has a type error  
because 'id' (from the type system's perspective) is a pointer to a  
struct and not a pointer to an Objective-C object.  Function 'f3' has  
a type error because we cannot dereference 'p'.

So, as far as regions are concerned, a region with an LvalueType of  
ObjCQualifiedIdType has no RValueType.  We essentially have no way of  
referring to the "thing" that chunk of memory represents.  There is no  
name for that concept.

I added "isBoundable" to basically return false for  
ObjCInterfaceTypes, but there may be others.  This basically means  
that the StoreManager cannot directly bind values to that region, but  
may be able to bind values to subregions that hang off that region  
(think fields, instance variables, etc.).  The code in CFRefCount.cpp  
that invalidates parameters passed-by-reference to "unknown" functions  
conjures up a new symbol value by getting the RValueType of the  
region.  We cannot do this with ObjCQualifiedIdTypes.  On the plus  
side this means that the object itself won't be "invalidated",  
although its instance variables could potentially be altered.

I think the better solution might be to not have a "isBoundable" and  
instead have "getRValueType" return a variant type that means there is  
an RValueType or there isn't.



More information about the cfe-commits mailing list