[cfe-dev] [Patch] add KillStruct() to RegionStore
Ted Kremenek
kremenek at apple.com
Mon Jan 12 15:23:44 PST 2009
This looks great! Two comments:
+const GRState* RegionStoreManager::KillStruct(const GRState* St,
+ const TypedRegion* R){
+ GRStateRef state(St, StateMgr);
+
+ // Kill the struct region because it is assigned "unknown".
+ St = state.add<RegionKills>(R);
+
+ // Set the default value of the struct region to "unknown".
+ St = state.set<RegionDefaultValue>(R, UnknownVal());
+
+ // Remove the struct region from the RegionViews. It could only be
a "view" of
+ // its super region.
+ St = RemoveRegionView(St, R, R->getSuperRegion());
Hmm. I'm looking at this again, I guess removing the view of 'R' from
its super region doesn't make sense. It's just the values bound to
'R' that change, not the fact that 'R' is a view of its super region.
+
+ Store store = St->getStore();
+ RegionBindingsTy B = GetRegionBindings(store);
+
+ // Remove all bindings for the subregions of the struct.
+ for (RegionBindingsTy::iterator I = B.begin(), E = B.end(); I != E;
++I) {
+ const MemRegion* r = I.getKey();
+ if (const SubRegion* sr = dyn_cast<SubRegion>(r))
+ if (sr->isSubRegionOf(R))
+ store = Remove(store, Loc::MakeVal(sr));
I am wondering if we also need to remove bindings for views of 'sr'.
That is, iterate over the views of 'sr' and remove any bindings from
state. What do you think? I guess it depends on how we decide to
bind values in weird cases where people abuse the type system.
+ }
+
+ return StateMgr.MakeStateWithStore(St, store);
+}
+
On Jan 10, 2009, at 3:12 AM, Zhongxing Xu wrote:
>
>
> On Sat, Jan 10, 2009 at 3:46 PM, Ted Kremenek <kremenek at apple.com>
> wrote:
> On Jan 8, 2009, at 5:36 PM, Zhongxing Xu wrote:
>
> Index: lib/Analysis/RegionStore.cpp
> ===================================================================
> --- lib/Analysis/RegionStore.cpp (版本 61900)
>
>
> + if (V.isUnknown())
> + return KillStruct(St, R);
> +
>
> When precisely can V.isUnknown() be true when the value is a
> struct? (test case please).
>
> We already have that test case. It is the f5() in test/Analysis/
> array-struct.c.
>
> Great! We should add a comment to that test case the says what part
> of the analyzer/region store is getting tested.
>
> Done.
>
>
>
> +const GRState* RegionStoreManager::KillStruct(const GRState* St,
> + const TypedRegion* R){
> + GRStateRef state(St, StateMgr);
> + // Set the default value of the struct region to UnknownVal.
> + St = state.set<RegionDefaultValue>(R, UnknownVal());
>
> Interesting. Do we need the killset anymore, or are we going to
> model "killed values" in this way?
>
> I think we still need killset. The regions in killset are ones we
> query its binding directly. The regions in RegionDefaultValue are
> ones whose subregions we query bindings for. I haven't had a way to
> combine them.
>
> I believe I might be confused about some basic concepts. Here is
> how I interpreted things.
>
> The "killset" is part of the state, and represents those regions
> whose values have been changed (via direct assignment) after the
> entry to the analyzed function. This way we don't need to
> explicitly bind initial values to regions and instead lazily infer
> their bindings.
>
> According to comments in RegionStore, the "default value" map
> (RegionDefaultValue) is used to track "what regions have a default
> value of 0 if they have no bound value and have not been killed."
>
> From the patch I see 'KillStruct' being used in the following way:
>
> const GRState*
> RegionStoreManager::BindStruct(const GRState* St, const TypedRegion*
> R, SVal V){
> // FIXME: Verify that we should use getRValueType or getLValueType.
> QualType T = R->getRValueType(getContext());
> assert(T->isStructureType());
>
> RecordType* RT = cast<RecordType>(T.getTypePtr());
>
> RecordDecl* RD = RT->getDecl();
> assert(RD->isDefinition());
>
> if (V.isUnknown())
> return KillStruct(St, R)
> ...
>
> Two things occur to me:
>
> (1) We should always be adding any region directly assigned to the
> killset. Doesn't that include structs?
>
> Yes. I thought we would never query a struct region's binding like
> we never do it to an array region. But later I realized I was wrong.
> I've done this step in the new patch.
>
> And, I think we should add a region to the killset *only* when it is
> assigned "unknown" directly. Because if it is assigned other value,
> we would have its binding in the region bindings. It is redundant to
> add it to the killset.
>
>
>
> (2) After assigning the value "unknown" to the struct, the values of
> its fields should not be 0 (as indicated by the comments for
> RegionDefaultValue). That doesn't make sense to me. Shouldn't they
> just be "unknown"?
>
> In other words, regardless of whether V.isUnknown() == true (in the
> above code snippet) we should always do (1) and then just remove any
> bindings to struct and it's fields. Adding entries to
> RegionDefaultValue (i.e., (2)) doesn't make sense to me, so I think
> I'm just missing something and don't really understand the overall
> design.
>
> RegionDefaultValue was originally designed to include regions which
> have default values of 0. But later I find we could have default
> values other than 0. This is just a case that we need it, since we
> would query the bindings of the subregions of the struct region that
> is killed (assigned "unknown"). If we don't set the struct region's
> default value, we would have to add all subregions of the struct
> region to the killset. Now that we set the struct region's default
> value, we can just remove the subregions of the struct region from
> RegionBindings.
>
>
>
> Ah, I forgot that point. Is this also known as persistent data
> structure?
>
> Yes it is. The term "purely functional data structures" comes from
> the functional programming mindset. Okasaki has an excellent book
> on that topic:
>
> http://books.google.com/books?id=SxPzSTcTalAC&dq=purely+functional+data+structures&printsec=frontcover&source=bn&hl=en&sa=X&oi=book_result&resnum=4&ct=result
>
> Thanks.
>
>
>
>
> Do we also need to remove region views for the regions that are
> killed, or should we dispense with that GDM entry entirely?
>
> I think region views are orthogonal to this one. Region views are
> used to cast region back and forth between typed and untyped ones.
> Here we only handle the region bindings.
>
> "Views" are just a specific type of subregions (whose bindings are
> all getting nuked by KillStruct). The GDM entry "RegionViews" is
> just a back-mapping from a region to its subregions. If we remove
> all of those bindings why do we need to keep that backmapping around
> since none of them bind to any value? Removing stale data from the
> state allows better caching.
>
> Yes, I've done this in the new patch.
>
>
>
> As a meta comment, it would probably be good to add comments to the
> top of RegionStore that documents the overall design. More
> specifically, we should mention how the different GDM pieces are
> used, what's the overall abstraction of how regions bind to values,
> how we model "views" of regions (i.e., what they are and what
> purpose they serve) and so forth. I feel that some of my confusion
> is stemming from not completely understanding the design as well as
> I thought I did.
>
> Yes. I should have done that. But I didn't do it because I feel some
> designs are not fixed.
> <killstruct2.patch>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20090112/449eab0f/attachment.html>
More information about the cfe-dev
mailing list