[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