[cfe-dev] Clang Static Analyzer - tracking object value

Jordan Rose jordan_rose at apple.com
Mon Apr 29 19:06:38 PDT 2013

Aack, no, this is not how it works. :-)

From a checker-writer's perspective, conjureSymbolVal() always creates a new symbol. Now, that symbol isn't really unique, because it's cheaper if we reuse symbols along multiple paths, but you really can't use it to represent the same symbol that the analyzer core will create.

Instead, what you want is a post-call check, where you can then use getSVal on the constructor expression to get the return value (which is usually the region that was just constructed*). Unfortunately...

> Next, my problem is with detecting when members of the transaction object is called. I was trying to get the SymbolRef of the object whose member is called:
> const CXXInstanceCall* instanceCall = llvm::dyn_cast<CXXInstanceCall>(&call);
> ...
> SymbolRef transactionObjectSymbol = instanceCall->getCXXThisVal().getAsSymbol();
> But I find that this SymbolRef is always NULL. Why is that?

...not every C++ object has an associated symbol. As we describe in "Building a Checker in 24 Hours", a symbol is only used to represent a value that the analyzer can't reason about. What you're interested in here is the region, which represents the memory backing the abstract C++ object. Unfortunately...

...a lot of C++ objects are value objects, which means they get copied from place to place, and currently it's up to checker writers to determine when that copy happens. Anna actually started sketching out a C++ iterator checker and realized that this problem was nontrivial (though by no means insurmountable).

(Aside: if the region is more important than the symbol, why did we choose to attach our stream information to the symbol in SimpleStreamChecker? Well, the type of a POSIX stream is FILE*, but the pointer-ness of it is essentially an implementation detail. It's more important to associate the state with the return value of fopen(). Indeed, the same logic in SimpleStreamChecker could be used for the raw file descriptors used by open(), write(), and close().)

That's sort of where we stand today. I don't have a good answer for you on how to deal with C++ value objects. Sorry!


* This "usually" is another problem for you—if we're constructing an anonymous temporary object like 'MyHandler(this)', the expression may result in an rvalue, which means the value represents a collection of struct field bindings instead of an actual region in memory. I would not worry about this case so much right now, though.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20130429/336a8991/attachment.html>

More information about the cfe-dev mailing list