aaron.ballman added a reviewer: NoQ.
aaron.ballman added a subscriber: NoQ.
aaron.ballman added a comment.
Herald added a subscriber: Charusso.

In D83717#2366598 <https://reviews.llvm.org/D83717#2366598>, @gamesh411 wrote:

>> Just to make sure we're on the same page -- the current approach is not 
>> flow-sensitive, and so my concern is that it won't report any true positives 
>> (not that it will be prone to false positives).
>
> Sorry about that. You are absolutely right; what I was trying to say is 
> CallGraph-based.
>
> Just some thoughts on this example:
>
> In D83717#2279263 <https://reviews.llvm.org/D83717#2279263>, @aaron.ballman 
> wrote:
>
>> One of the concerns I have with this not being a flow-sensitive check is 
>> that most of the bad situations are not going to be caught by the clang-tidy 
>> version of the check. The CERT rules show contrived code examples, but the 
>> more frequent issue looks like:
>>
>>   void cleanup(struct whatever *ptr) {
>>     assert(ptr); // This potentially calls abort()
>>     free(ptr->buffer);
>>     free(ptr);
>>   }
>>   ...
>
> What I have in support of this approach is this reasoning:
> If a handler is used where either branch can abort then that branch is 
> expected to be taken. Otherwise it is dead code. I would argue then, that 
> this abortion should be refactored out of the handler function to ensure 
> well-defined behaviour in every possible case.

If the assert was directly within the handler code, then sure. However, 
consider a situation like this:

  struct Something {
    Something(int *ip) { assert(ip); ... }
    ...
  };

where the use of the assertion is far removed from the fact that it's being 
used within a handler.

> As a counter-argument; suppose that there is a function that is used as both 
> an exit-handler and as a simple invocation. In this case, I can understand if 
> one would not want to factor the abortion logic out, or possibly pass flags 
> around.

Yes, this is exactly the situation I'm worried about.

> Then to this remark:
>
>> The fact that we're not looking through the call sites (even without 
>> cross-TU support) means the check isn't going to catch the most problematic 
>> cases. You could modify the called function collector to gather this a bit 
>> better, but you'd issue false positives in flow-sensitive situations like:
>>
>>   void some_cleanup_func(void) {
>>     for (size_t idx = 0; idx < GlobalElementCount; ++idx) {
>>       struct whatever *ptr = GlobalElement[idx];
>>       if (ptr) {
>>         // Now we know abort() won't be called
>>         cleanup(ptr);
>>       }
>>     }
>>   }
>
> The current approach definitely does not take 'adjacent' call-sites into 
> account (not to mention CTU ones).
> In this regard I also tend to see the benefit of this being a ClangSA checker 
> as that would solve 3 problems at once:
>
> 1. Being path-sensitive, so we can explain how we got to the erroneous 
> program-point
> 2. It utilizes CTU mode to take callsites from other TU-s into account
> 3. Runtime-stack building is implicitly done by ExprEngine as a side effect 
> of symbolic execution

Agreed.

> Counter-argument:
> But using ClangSA also introduces a big challenge.
> ClangSA analyzes all top-level functions during analysis. However I don't 
> know if it understands the concept of exit-handlers, and I don't know a way 
> of 'triggering' an analysis 'on-exit' so to speak.
> So AFAIK this model of analyzing only top-level functions is a limitation 
> when it comes to modelling the program behaviour 'on-exit'.

I'm hoping someone more well-versed in the details of the static analyzer can 
speak to this point. @NoQ @Szelethus others?

> sidenote:
> To validate this claim I have dumped the exploded graph of the following file:
>
>   #include <cstdlib>
>   #include <iostream>
>   
>   void f() {
>     std::cout << "handler f";
>   };
>   
>   int main() {
>     std::atexit(f);
>   }
>
> And it has no mention of std::cout being used, so I concluded, that ClangSA 
> does not model the 'on-exit' behaviour.
>
> I wanted to clear these issues before I made the documentation.
> Thanks for the effort and the tips on evaluating the solution, I will do some 
> more exploration.

Thank you for looking into this! If it turns out that there's some reason why 
the static analyzer cannot be at least as good of a home for the functionality 
as clang-tidy, that would be really interesting to learn. Either there are 
improvements we could consider making to the static analyzer, or we could leave 
the check in clang-tidy despite the limitations, but there's still a path 
forward.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D83717/new/

https://reviews.llvm.org/D83717

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to