[analyzer] Calls to `final` virtual methods are not devirtualized, so dynamic dispatch bifurcation explores an override that cannot exist
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
When a virtual method is declared `final` (or its class is), and the receiver's static type is that class, the callee can be uniquely determined. The analyzer still treats the call as a dynamic dispatch with an unknown target, returns a `RuntimeDefinition` carrying a dispatch region and `dynDispatchBifurcate()` splits the state, and on one branch the call is evaluated conservatively. On that branch the return value is a fresh conjured symbol, so two calls to the same `final` method on the same pointer are not correlated.
## Reproducer
```c++
struct Msg
{
virtual ~Msg() {}
virtual unsigned cmd() const = 0;
};
struct Ctrl : Msg
{
unsigned c;
unsigned cmd() const final { return c; } // final: no override can exist
};
void clang_analyzer_dump(unsigned);
void clang_analyzer_eval(bool);
void test(Ctrl* p)
{
clang_analyzer_dump(p->cmd());
clang_analyzer_eval(p->cmd() == p->cmd());
}
```
command line is:
```sh
clang++ --analyze -std=gnu++17 -Xclang -analyzer-checker=core,debug.ExprInspection repro.cpp
```
The log is:
```
repro.cpp:18:3: warning: conj_$6{unsigned int, LC1, S2393, #1}
repro.cpp:18:3: warning: reg_$29},0 S64b,struct Ctrl}.c>
repro.cpp:19:3: warning: FALSE
repro.cpp:19:3: warning: TRUE
```
This issues is derived from: https://github.com/llvm/llvm-project/issues/222699 and original code reproducing it is [available](https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(filename:'1',fontScale:14,fontUsePx:'0',j:1,lang:c%2B%2B,selection:(endColumn:1,endLineNumber:18,positionColumn:1,positionLineNumber:18,selectionStartColumn:1,selectionStartLineNumber:18,startColumn:1,startLineNumber:18),source:'struct+Msg%0A%7B%0A++virtual+~Msg()+%7B%7D%0A++virtual+unsigned+cmd()+const+%3D+0%3B%0A%7D%3B%0A%0Astruct+Ctrl+:+Msg%0A%7B%0A++unsigned+c%3B%0A++explicit+Ctrl(unsigned+cmd)+:+c(cmd)+%7B%7D%0A++unsigned+cmd()+const+final+%7B+return+c%3B+%7D%0A%7D%3B%0A%0Astatic+unsigned+slots(const+Ctrl*+m)%0A%7B%0A++return+m-%3Ecmd()+%3D%3D+12+%3F+2+:+1%3B%0A%7D%0A%0Avoid+dispatch(Ctrl*+c)%0A%7B%0A++if+(c-%3Ecmd()+!!%3D+12)%0A++++return%3B%0A%0A++unsigned*+d+%3D+new+unsigned%5Bslots(c)%5D%3B%0A++d%5B1%5D+%3D+0%3B++//+reported+here%0A++delete%5B%5D+d%3B%0A%7D%0A%0Astatic+Ctrl+incoming(12)%3B%0Astatic+void+(*handler)(Ctrl*)+%3D+dispatch%3B%0A%0Aint+main()%0A%7B%0A++handler(%26incoming)%3B%0A++return+0%3B%0A%7D%0A'),l:'5',n:'0',o:'C%2B%2B+source+%231',t:'0')),k:54.412532637075714,l:'4',n:'0',o:'',s:0,t:'0'),(g:!((h:compiler,i:(compiler:clang_trunk,filters:(b:'1',binary:'1',binaryObject:'0',commentOnly:'1',debugCalls:'1',demangle:'1',directives:'1',execute:'1',intel:'1',libraryCode:'1',trim:'1',verboseDemangling:'0'),flagsViewOpen:'1',fontScale:14,fontUsePx:'0',j:1,lang:c%2B%2B,libs:!(),options:'--analyze+-Xclang+-analyzer-checker%3Dcore,security.ArrayBound+-Xclang+-analyzer-output%3Dtext',overrides:!(),selection:(endColumn:1,endLineNumber:1,positionColumn:1,positionLineNumber:1,selectionStartColumn:1,selectionStartLineNumber:1,startColumn:1,startLineNumber:1),source:1),l:'5',n:'0',o:'+x86-64+clang+(trunk)+(Editor+%231)',t:'0'),(h:output,i:(compilerName:'x86-64+clang+3.4+(assertions)',editorid:1,fontScale:14,fontUsePx:'0',j:1,wrap:'1'),l:'5',n:'0',o:'Output+of+x86-64+clang+(trunk)+(Compiler+%231)',t:'0')),header:(),k:45.587467362924286,l:'4',m:100,n:'0',o:'',s:1,t:'0')),l:'2',n:'0',o:'',t:'0')),version:4).
Contributor guide
Assessment
This issue has not been assessed yet.