digitalmars.D.bugs - [Issue 15579] New: extern(C++) interfaces/multiple-inheritence
- via Digitalmars-d-bugs (98/98) Jan 18 2016 https://issues.dlang.org/show_bug.cgi?id=15579
https://issues.dlang.org/show_bug.cgi?id=15579 Issue ID: 15579 Summary: extern(C++) interfaces/multiple-inheritence Product: D Version: D2 Hardware: All OS: All Status: NEW Severity: enhancement Priority: P1 Component: dmd Assignee: nobody puremagic.com Reporter: turkeyman gmail.com I'm noticing some differences in struct layout between C++ and D. I'm doing tests by making some classes, putting members in between the locations I expect vtable pointers to be placed, and then comparing the offsets of the members. This is what I'm seeing: In C++: class Base { virtual ~Base() {} size_t x; }; class Interface { virtual Method() = 0; }; class Derived : public Base, public Interface { size_t y; }; In C++, Derived is: { void *__Base_vtable; size_t x; void *__Interface_vtable; size_t y; } This is as I expect. ------------------- D: extern(C++) class Base { ~this() {} size_t x; } extern(C++) interface Interface { abstract Method(); } extern(C++) class Derived : Base, Interface { size_t y; } Derived appears to be: { void *__Base_vtable; size_t x; size_t y; } So, D seems to think 'y' is where Interface_vtable should be... I'm not sure where D thinks the Interface_vtable pointer actually is. What's interesting though, is that I can call 'Method' introduced by Interface, D does try and call something... which means it must get a vtable pointer somewhere, but it crashes on a bad function pointer, so something goes wrong. Digging into the bad virtual call, I get this: (Note, my test case is not exactly what's above; in this test, Interface has a few functions and I'm calling the 4th one in the vtable) 00007FF72DB7381B mov rbx,qword ptr [this] // rbx is 'this' 00007FF72DB7381F mov rcx,qword ptr [rbx+10h] // rcx is [this+10h], which is actually the proper location for Interface_vtable, contrary to what I found above Surprisingly, this looks good. rcx is Interface_vtable, and it found it at the location I expect, which means my test above was lying to me about the location of 'y'. But here it gets a little weird... 00007FF72DB73823 mov rcx,qword ptr [rcx] // what's this? ie, rcx = rcx[0] rcx is now the first function pointer in the vtable; NOT the function I'm calling, which is actually [rcx+18h]! 00007FF72DB73826 sub rsp,20h // nothing of interest 00007FF72DB7382A mov rax,qword ptr [rcx] // dereferencing the function pointer! rax is now the first 8 bytes of program code of the first function in the vtable 00007FF72DB7382D call qword ptr [rax+18h] // calling rax+18h If rax were rcx from the second operation above, 18h is the proper vtable offset of the function I'm trying to call, and this would be correct, but there are 2 bonus dereferences there that shouldn't be. I don't know how interfaces are implemented in D, is this showing some relationship to normal D interface calls? This is certainly not proper extern(C++) behaviour. The offset of y seems confused, and the extra 2 dereferences shouldn't be there. Tests are with DMD-Win64 compared against MSC2015-Win64. --
Jan 18 2016