extern(C++, ns)

Manu via Digitalmars-d digitalmars-d at puremagic.com
Mon Jan 18 00:47:13 PST 2016


On 18 January 2016 at 15:32, Manu <turkeyman at gmail.com> wrote:
> On 15 January 2016 at 12:25, Walter Bright via Digitalmars-d
> <digitalmars-d at puremagic.com> wrote:
>> On 1/14/2016 6:24 PM, Walter Bright wrote:
>>>
>>> On 1/13/2016 9:39 PM, Walter Bright wrote:
>>>>
>>>>    https://issues.dlang.org/show_bug.cgi?id=15565
>>>
>>>
>>> https://issues.dlang.org/show_bug.cgi?id=15565
>>
>>
>> I meant:
>>
>>   https://github.com/D-Programming-Language/dmd/pull/5351
>
> Confirm that problem is solved in latest daily.
>
> Next one:
>
> void f()
> {
>   j = 0; // works as expected
>   k = 0; // fail
> }
> private:
> __gshared int j;
> extern(C++, ns) __gshared int k;
>
>> Error: module x variable x.ns.k is private

Next problem:


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.


More information about the Digitalmars-d mailing list