[cfe-commits] r61147 - in /cfe/trunk: lib/Analysis/CFRefCount.cpp test/Analysis/uninit-vals-ps.c

Ted Kremenek kremenek at apple.com
Tue Mar 10 14:08:29 PDT 2009


On Mar 10, 2009, at 12:40 AM, Zhongxing Xu wrote:

>
> I see your point. But how can we recognize which casts are semantic  
> changes and which are sugar typed?
> I doubt there is a consistent rule for this.
>

I'm fairly certain there is a consistent rule for this.  Actually, it  
is very simple: semantic changes due to type views on regions occur  
when the view would result in the chunk of memory being interpreted  
differently.  In the case of typedefs, they are just sugar for the  
underlying type, and don't change the semantics.

I've worked out a simple example to explain a proposal I have for  
possibly dealing with this issue.  The basic rules are as follows:

(a) Symbolic regions potentially don't have types other than "void*".   
That is, they are just chunks of memory.

(b) We "canonicalize" regions when performing bindings to them, but  
don't need to canonicalize regions when they are used as values for  
expressions (see example below).

(c) We strip away type views when performing pointer comparisons.  The  
type-checking in the frontend will tell us whether or not a pointer  
comparison is legal.

Here is my example.  There are other cases to consider, such as how to  
handle Objective-C and C++ objects, but I think this is a good  
starting point:


typedef struct s* MyPointer;
void* foo(void);

    void bar(void) {
1.   MyPointer q = foo();
2.   void *r = q;
3.   struct s* p = r;
4.   if (p == q)
5.      q->f = 10;
6.   if (q->f == 10)
         ...
7.   if (p->f == 10)
    }


What happens:

(a) On line 1 'foo()' evaluates to SymbolicRegion(Sym0).

(b) On line 1 the value of (a) is then casted to
     TypedViewRegion(MyPointer, SymbolicRegion(Sym0)).

(c) On line 1 that value is bound to 'q'.  Internally it is stored as
     'q' => TypedViewRegion(MyPointer, SymbolicRegion(Sym0)).  Observe  
that the
     typedef is retained as it is used as a value in the binding and  
not the key.

     Note that the syntax:

      'q' => some value

     is shorthand for

       VarRegion('q') => some value

(d) On line 2 we perform a load from 'q' (i.e., VarRegion('q')) to get  
the value
     TypedViewRegion(MyPointer, SymbolicRegion(Sym0)).

(e) On line 2 we cast (d) to void*.  This results
     in stripping the 'TypedViewRegion' and getting  
'SymbolicRegion(Sym0)'.  This
     value is directly bound to 'r' to get the binding
    'r' => SymbolicRegion(Sym0).

(f) On line 3 we load from 'r' to get SymbolicRegion(Sym0).

(g) On line 3 we cast (f) to 'struct s*', leaving us with the region
     TypedViewRegion(struct s*, SymbolicRegion(Sym0)).

(h) On line 3 we bound the value of (g) to 'p'.  This leaves us with the
     binding 'p' => TypedViewRegion(struct s*, SymbolicRegion(Sym0)).

(i) On line 4 we load both p and q, getting the values
      TypedViewRegion(struct s*, SymbolicRegion(Sym0)) (for 'p') and
      TypedViewRegion(MyPointer, SymbolicRegion(Sym0)) (for 'q').

    We then do a pointer comparison by erasing their "views" and see  
if they
    refer to the same memory object.  This means getting the first  
"non-view"
    ancestor region.  In this case, the ancestor region is  
SymbolicRegion(Sym0)
    in both cases.  This causes 'p == q' to evaluate to true.

    The rationale behind this view-stripping is that we are just  
comparing
    pointer addresses at this point, and "views" reason about the  
interpretation
    of the bytes within a region but not the address of the region  
itself.

    The "base region" doesn't have to be a SymbolicRegion. For example  
it could
    be a VarRegion.

(j) On line 5 we evaluate the l-value of 'q->f'.  This value is
     FieldRegion('f',TypedViewRegion(MyPointer, SymbolicRegion(Sym0))).

(k) On line 5 we ask the store manager to store '10' to the l-value  
computed
     at (j).  Internally, within the StoreManager, we translate:

       FieldRegion('f',TypedViewRegion(MyPointer,  
SymbolicRegion(Sym0))).

     to:

       FieldRegion('f',TypedViewRegion(struct s*,  
SymbolicRegion(Sym0))).

     and then bind '10' to the latter.

     Here we have "de-sugared" the TypedViewRegion so that all  
typedefs are
     translated to the underlying type.

     The rationale for this de-sugaring is that we want to  
"canonicalize" the key
     (and *not* the value) in the binding. This makes retrievals from  
the store
     easy in the presence of typedefs (which don't change the  
semantics of how a
     region is interpreted).

(l) One line 6 we compute the l-value of 'q->f' to be
     FieldRegion('f',TypedViewRegion(MyPointer,SymbolicRegion(0))) and  
then ask
     the store manager to load from that region.

     Within the StoreManager, the key is again canonicalized to
     FieldRegion('f',TypedViewRegion(struct s*, SymbolicRegion(0))).

     The retrieval from the store then uses this key, getting the  
value 10.

(m) Similarly, on line 7 we compute the l-value of 'p->f' to be
     FieldRegion('f',TypedViewRegion(struct s*, SymbolicRegion(0)))  
and then ask
     the store manager to load from that region.

     Within the StoreManager that key is also canonicalized, but since  
it is
     already canonical we just do the load.




More information about the cfe-commits mailing list