Bug 15610 – extern(C++) multiple inheritance - calling with wrong 'this' ptr

Status
RESOLVED
Resolution
FIXED
Severity
blocker
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
x86_64
OS
Windows
Creation time
2016-01-26T04:53:00Z
Last change time
2016-03-19T20:21:46Z
Keywords
C++
Assigned to
nobody
Creator
turkeyman

Attachments

IDFilenameSummaryContent-TypeSize
1580test.ziptest caseapplication/x-zip-compressed4862

Comments

Comment #0 by turkeyman — 2016-01-26T04:53:26Z
I'm seeing a case where 'this' being passed to a C++ function is wrong. C++ multiple-inheritance calls expect that 'this' pointers are adjusted by the offset of the base class. Something like this: extern(C++) class Base { ~this() {} size_t i; } // Base is 16 bytes extern(C++) interface I { void f(); } extern(C++) class C : Base, I { final override void f(); } C is: { _vtbl, i, _I_vtbl (this+16h) } void code(C c) { // crash: c.f(); passes this = 'c' to f(), but C++ expects 'c + C._I_vtbl.offsetof' } In this example, I have a class instance 'c', and I'm calling 'f' (introduced by the interface), which is marked final, so D is able to perform a static call to the C++ function with no vtable lookup. I have managed to get this to link, and D does call the correct C++ function, but D doesn't seem to adjust the 'this' pointer correctly for the call. The C++ function 'f' expects that 'this' is an I pointer (not a C pointer), which is offset by sizeof(Base) from the start of C, but D just passes 'this' unaltered. The result is that within C::f(), the C++ code expects that 'C' is at 'this-16h', and everything is 16 bytes out of phase leading to a prompt crash. TL;DR: Calling of multiple-inherited C++ interfaces requires adjustment of the 'this' pointer before making the call.
Comment #1 by bugzilla — 2016-01-27T23:53:34Z
This was addressed by: https://github.com/D-Programming-Language/dmd/pull/5364 Since the code snippet you post here looks like the test case in 5364, I don't see what the different is. > Something like this: I cannot do anything with this, since it already looks like the test case in 5364. Clearly, something DIFFERENT is happening if it fails for you, meaning it is DIFFERENT code in some way that you have not posted. PLEASE submit test cases with reproducible code snippets. "Something like this" is not going to work. So many times I have tried to fill in what the missing pieces might be, only to fail and eventually discover that the submitter had omitted critical information, not realizing that it was critical.
Comment #2 by bugzilla — 2016-01-28T00:05:28Z
I did some guesswork, and figured out that if you remove the 'final', it will work successfully, so I suggest that as a workaround for the moment.
Comment #3 by turkeyman — 2016-01-28T00:19:59Z
Okay, I'll give that a shot. Incidentally, 99% of my functions are final, and about 80% of my virtuals are also final. It'd be good to make finalised virtuals work properly a priority. Final also has a mangling problem.
Comment #4 by bugzilla — 2016-01-28T05:44:46Z
Comment #5 by turkeyman — 2016-01-28T12:15:36Z
Created attachment 1580 test case
Comment #6 by turkeyman — 2016-01-28T12:17:37Z
Reduced a test case. You'll see a crash as it tries to call the non vtable member 'BAADFOOD'. Bonus points: void test() is extern(C) because extern(C++) doesn't mangle the type properly; doesn't link.
Comment #7 by turkeyman — 2016-01-28T12:20:42Z
Also, I don't think this particular crash looks the same as the situation of my other crash; neither rax or rcx are messed up in quite the same way, but they are both messed up, so it might be related. The other case is that the pointers are dereferenced one level too deep before the call. This case appears that that the wrong offset is used as the vtable pointer.
Comment #8 by github-bugzilla — 2016-01-31T01:34:57Z
Commits pushed to master at https://github.com/D-Programming-Language/dmd https://github.com/D-Programming-Language/dmd/commit/f46f2197f458b4f242484b486302a383e70ceac4 fix Issue 15610 - extern(C++) multiple inheritance - calling with wrong 'this' ptr https://github.com/D-Programming-Language/dmd/commit/84f6aaf592c6b4526a24f43d1bbdca77b4943b74 Merge pull request #5372 from WalterBright/fix15610 fix Issue 15610 - extern(C++) multiple inheritance - calling with wro…
Comment #9 by github-bugzilla — 2016-03-19T20:21:46Z
Commits pushed to stable at https://github.com/D-Programming-Language/dmd https://github.com/D-Programming-Language/dmd/commit/f46f2197f458b4f242484b486302a383e70ceac4 fix Issue 15610 - extern(C++) multiple inheritance - calling with wrong 'this' ptr https://github.com/D-Programming-Language/dmd/commit/84f6aaf592c6b4526a24f43d1bbdca77b4943b74 Merge pull request #5372 from WalterBright/fix15610