[cfe-dev] Static Analyzer : Query regarding how symbols are marked as dead

Jordan Rose jordan_rose at apple.com
Fri Mar 15 09:51:00 PDT 2013


On Mar 14, 2013, at 23:08 , Karthik Bhat <blitz.opensource at gmail.com> wrote:

> Thanks Jordan. I will try to upload my changes so that you can access the same.
> 
> I have a small doubt. Please excuse me if it sounds a bit silly as i'm new to clang static analyzer.
> 
> How do i load the external AST file in the same ASTContext as the current compiler instance ASTContext?
> 
> I'm currently using LoadFromASTFile to get the ASTUnit. Did you mean i need to use ASTImporter class to import the Decl in this AST into current AST( i.e. CI.getASTContext()) ?

I'm not entirely familiar with it myself; I mentioned it to Doug Gregor yesterday and he said the usual way would be to use ASTReader directly, rather than going through LoadFromASTFile. I'm not sure what happens if two files have the same static variable, though; they might get merged, and that would be Bad.

Several years ago there was an experimental project (efforts led by either Ted Kremenek or Zhongxing Xu) to do something similar to what you're doing, with multiple ASTContexts. That tended not to work very well because (1) it turns out much of the analyzer depends on the invariants that only hold within a single ASTContext (e.g. canonical types can be compared by pointer identity), and (2) the cost of marshalling when going between AST contexts was a significant performance hit.

For your actual example, I'm guessing you're handling arguments but not return values. I'm not exactly sure what would be wrong here, but return value processing is handled in ExprEngine::processCallExit, so that might be a place to start looking.

Jordan


> Currently the code flow looks like-
> 
> 1. In getRuntimeDefinition() if a function body is null i'm using LoadFromASTFile to get the ASTUnit (Unit).
>     ( e.g. ASTUnit* Unit1 =  ASTUnit::LoadFromASTFile(funcDeclFile,Diags1,FileSystemOpt1); )
> 
> 2. Get the TranslationUnitDecl from ASTUnit and traverse it to get the appropriate FunctionDecl.
> 
> 3. Use this FunctionDecl to create and return the RuntimeDefinition object.
> 
> 4. I'm also storing the corresponding SourceManager and propagating it  so that the Diagnostic Engine can use this SourceManager to decode the SourceLocation correctly which might be present in the loaded file.
> 
> 
> P.S. I'm able to detect and report double free properly now across TU. I had made a small mistake in code. But i'm getting a lot of false alarm in case 1 mentioned above were it is reporting memory leak even though the allocated memory is freed by the called function. i.e.-
> 
> File2.c has -
> 
> char* mymalloc()
> {
>   char* kar = (char*) malloc(sizeof(char));
>   return kar;
> }
> 
> File1.c has-
> 
> extern char* mymalloc();
> int main()
> {
> 
>   char* q = mymalloc();
>   free(q);
>   return 0;
> }
> 
> In the above code during processCallExit in ExprEngine Core marks symbol for variable kar in mymalloc as dead although the MemoryRegion is referred in File1.c  after aliasing it to q.
> 
> Any inputs appreciated and thanks for your prompt replies.
> 
> Regards
> Karthik
> 
> 
> On Thu, Mar 14, 2013 at 11:17 PM, Jordan Rose <jordan_rose at apple.com> wrote:
> I think I'd have to see your code to be sure. One thing that's very important is that you load the external AST file in the same ASTContext. Other than that, though, your approach does seem reasonable.
> 
> Can you post your modifications somewhere? I'll try to look over them when I have time and see if I see anything obviously strange.
> Jordan
> 
> 
> On Mar 13, 2013, at 3:51 , Karthik Bhat <blitz.opensource at gmail.com> wrote:
> 
>> Thanks Jordan. That was useful information. I also found  "A memory model for static analysis of C programs" by Ted also very useful.
>> 
>> I'm trying to implement IPA across TU for my internal project. The approach i'm using is i'm dumping .ast of all files using -emit-ast option. 
>> In case a function body is not found while analyzing i load the corresponding ast file having function definition and use this FunctionDecl with the current in-lining approach.
>> 
>> For example in the above code myFree()  is implemented in another file and i get the FunctionDecl by loading the ast and use this to inline. 
>> 
>> In this case though unfortunately region for 'q' does not contain a binding with the symbolic value returned from malloc. 
>> 
>> Am i doing something wrong here or missing out something?
>> 
>> Any inputs greatly appreciated.
>> 
>> Thanks
>> 
>> On Tue, Mar 12, 2013 at 10:09 PM, Jordan Rose <jordan_rose at apple.com> wrote:
>> Hello, Karthik. The analyzer does certain deliberate passes to clean up dead symbols and dead bindings in the state, generally before processing each statement. The top-level function for this is ExprEngine::ExprEngine::removeDead, and most of the high-level implementation is in the SymbolReaper class in ProgramState.h. The basic algorithm is pretty simple, though:
>> 
>> (1) Find out which expressions and variables are still live (LiveVariables). This is cached, per-function, context-insensitive information.
>> (2) Ask checkers which symbols are known to be in use, though potentially not live (checkLiveSymbols).
>> (3) Mark live any values associated with live expressions in the Environment. Remove all other bindings.
>> (4) Mark live any values accessible via the live regions in the Store. Remove all other bindings.
>> (5) Remove any constraints on dead symbols.
>> (6) Report dead symbols to the checkers, so that they can stop tracking information dependent on those symbols (checkDeadSymbols).
>> 
>> 
>> Your second question is easier: parameter-passing is modeled as a bind to the region for the parameter (a VarRegion whose associated declaration is a ParmVarDecl). So your myFree() example is essentially the same as this:
>> 
>> char *q = (char *)malloc(sizeof(char);
>> char *p = q;
>> free(p);
>> free(q); // warning
>> 
>> This happens in the 'enterStackFrame' method on the StoreManager, which uses CallEvent::getInitialStackFrameContents to figure out the initial bindings. You are correct that both the region for 'q' and the region for 'p' will contain a binding with the symbolic value returned from 'malloc'.
>> 
>> Does this help?
>> Jordan
>> 
>> P.S. For the record, this model of parameter passing will not be entirely correct once we model the destructors of C++ temporary regions; we will need to be more careful about non-POD objects being passed by value.
>> 
>> 
>> On Mar 11, 2013, at 1:09 , Karthik Bhat <blitz.opensource at gmail.com> wrote:
>> 
>> > Hi All,
>> > I was going through Malloc checker in clang Static analyzer. I had a few doubts-
>> >
>> > 1) How is a symbol marked as dead( How does clang static analyzer detect that a symbol is dead) ?
>> > E.g.
>> >
>> > char* myMalloc()
>> > {
>> >   char* p = (char*) malloc(sizeof(char));
>> >   return p;
>> > }
>> >
>> > int main()
>> > {
>> >   char* q = myMalloc();
>> >   return 0;
>> > }
>> >
>> > In the above example symbol assigned for p in myMalloc is alive till main(caller) exits right?
>> >
>> >
>> > 2) In case of IPA how are symbol propagated form one function to another in case it is passed as a parameter.
>> > E.g.
>> >
>> > void myFree(char* p)
>> > {
>> >    free(p);
>> > }
>> >
>> > int main()
>> > {
>> >
>> >   char* q = (char*) malloc(sizeof(char));
>> >   myFree(q);
>> >   free(q);
>> > }
>> >
>> > In the above example is it true that the parameter p in myFree is assigned the same symbol as that of q being passed to the function? If yes could someone guide me were this assignment of symbol happens?
>> >
>> >
>> > Thanks
>> > Karthik
>> >
>> >
>> > _______________________________________________
>> > cfe-dev mailing list
>> > cfe-dev at cs.uiuc.edu
>> > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
>> 
>> 
> 
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20130315/47323218/attachment.html>


More information about the cfe-dev mailing list