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.
signature.asc
Description: PGP signature

