https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69777
Eric Gallager <egallager at gcc dot gnu.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
Status|RESOLVED |NEW
Resolution|INVALID |---
Known to fail| |4.9.1, 5.5.0, 6.4.0, 7.2.1,
| |8.0
--- Comment #5 from Eric Gallager <egallager at gcc dot gnu.org> ---
(In reply to Vadim Zeitlin from comment #4)
> Sorry, I've somehow forgot to provide the example, but here it is in its
> most minimal form:
>
> namespace {
> struct AnonB {
> virtual bool foo() const = 0;
> virtual ~AnonB() {}
> };
> }
>
> struct RealB {
> virtual bool foo() const = 0;
> virtual ~RealB() {}
> };
>
> AnonB* create()
> {
> struct D : RealB {
> virtual bool foo() const { return true; }
> };
>
> return reinterpret_cast<AnonB*>(new D);
> }
>
> int main() {
> return create()->foo(); // please ignore the memory leak here
> }
>
> Compiling this without optimizations "works", while with -O2 or -O3 the
> program terminates due to a pure virtual function call and the code looks
> just like this:
>
> (gdb) disassemble
> Dump of assembler code for function main():
> => 0x0000000000400670 <+0>: mov edi,0x8
> 0x0000000000400675 <+5>: sub rsp,0x8
> 0x0000000000400679 <+9>: call 0x400660 <_Znwm@plt>
> 0x000000000040067e <+14>: mov QWORD PTR [rax],0x4008b0
> 0x0000000000400685 <+21>: mov rdi,rax
> 0x0000000000400688 <+24>: call 0x400650 <__cxa_pure_virtual@plt>
> End of assembler dump.
>
> Again, I understand that the program invokes undefined behaviour and the
> compiler is perfectly in its right to do what it does. But in practice casts
> such as above are always required when using COM with its QueryInterface()
> and it would be nice if the compiler could warn about this devirtualization
> because it can never be intentional, AFAICS.
>
> Also notice that giving the namespace a name (and replacing AnonB with
> NS::AnonB) also prevents the devirtualization from happening.
>
> Finally, I've tested this with (the originally reported) 4.9, 5.5, 6.4 and
> 7.2 and the behaviour is almost the same for all of them, but 7.2 does give
> this warning
>
> puredevirt.cpp: In function βint main()β:
> puredevirt.cpp:24:25: warning: β<anonymous>β is used uninitialized in this
> function [-Wuninitialized]
> return create()->foo();
> ~~~~~~~~~~~~~^~
>
> I guess this already partially addresses my request because at least there
> is a warning, but its wording is not especially clear. Looking at the
> disassembly
>
> (gdb) disassemble
> Dump of assembler code for function main:
> => 0x0000555555554600 <+0>: sub rsp,0x8
> 0x0000555555554604 <+4>: mov edi,0x8
> 0x0000555555554609 <+9>: call 0x5555555545e0 <_Znwm@plt>
> 0x000055555555460e <+14>: call 0x5555555545d0
> <__cxa_pure_virtual@plt>
> End of assembler dump.
>
> it becomes clear that it's the object on which foo() is called which is not
> initialized (i.e. it doesn't even bother loading its address before calling
> __cxa_pure_virtual, which makes sense), but it's not really obvious from
> just the error message.
Reopening; confirmed that the example only prints the -Wuninitialized warning,
but I get different disassembly, although that's probably due to target
differences. (my gdb doesn't disassemble it properly when optimized, but if I
use -save-temps and examine the assembly, I can see that it still contains the
call to __cxa_pure_virtual at least)