Control: found -1 0.7.91~git20230705.8eabf68-1
Control: tags -1 + upstream wontfix

Yes.
If we reduce f.cpp to
  #include "foo.hpp"
  int main() {
      foo* f = new foo_child;
      // ltrace doesn't report this one?
      f->virtual_foo();
      f->pure_virtual_foo();
  }
then
  $ nm -C f | grep foo
  0000000000001190 W foo::foo()
  0000000000001190 W foo::foo()
  00000000000011aa W foo_child::foo_child()
  00000000000011aa W foo_child::foo_child()
  0000000000003da0 V vtable for foo
  0000000000003d80 V vtable for foo_child

Because f is /actually/ fully virtual,
so calling either function actually looks like
  (f->_vtable[1])(f)
and the initialiser for f looks like
  f = malloc(...);
  memcpy(f._vtable, vtable for foo_child)

Whereas real
  #include "foo.hpp"
  int main() {
      foo_child g;
      // ltrace does report this one
      g.virtual_foo();
      g.pure_virtual_foo();
  }
yields
  $ nm -C f | grep foo
                   U foo::virtual_foo()
  00000000000011ba W foo::foo()
  00000000000011ba W foo::foo()
  00000000000011d4 W foo::~foo()
  00000000000011d4 W foo::~foo()
                   U foo_child::pure_virtual_foo()
  00000000000011ee W foo_child::foo_child()
  00000000000011ee W foo_child::foo_child()
  0000000000001218 W foo_child::~foo_child()
  0000000000001218 W foo_child::~foo_child()
  0000000000003d90 V vtable for foo
  0000000000003d70 V vtable for foo_child
because g is a concrete type so it's devirtualised,
so the calls /are/ actually
  foo_child::virtual_foo(&g)
&c.

You'd also see this from stack-allocated variables in more complex
scenarios that the compiler can't solve and devirtualise.

I'm pretty sure this is definitionally unsolvable.

Attachment: signature.asc
Description: PGP signature

Reply via email to