www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 22318] New: Calling virtual extern(C++) functions crashing or

https://issues.dlang.org/show_bug.cgi?id=22318

          Issue ID: 22318
           Summary: Calling virtual extern(C++) functions crashing or
                    wrong
           Product: D
           Version: D2
          Hardware: x86_64
                OS: Linux
            Status: NEW
          Severity: enhancement
          Priority: P1
         Component: dmd
          Assignee: nobody puremagic.com
          Reporter: tim.dlang t-online.de

While working on issue 22287 I found some other problems with extern(C++)
classes with constructors.

//////////////// test.d //////////////////

extern(C++):

class A
{
    this(int i);
    ~this();

    int i;
}

interface I
{
    int f() const;
}

class B : A, I
{
    this(int i);
    override int f() const;
}

class D : B
{
    this(int i)
    {
        super(i);
    }

    override int f() const
    {
        return i + 42;
    }
}

I createIFromCPP(char type, int i);
B createBFromCPP(char type, int i);
D createDFromCPP(int i);

I createIFromD(char type, int i)
{
    switch (type)
    {
    case 'B':
        return new B(i);
    case 'D':
        return new D(i);
    default:
        return null;
    }
}

B createBFromD(char type, int i)
{
    switch (type)
    {
    case 'B':
        return new B(i);
    case 'D':
        return new D(i);
    default:
        return null;
    }
}

D createDFromD(int i)
{
    return new D(i);
}

void runCPPTests();

extern(D) void main()
{
    {
        D d = new D(100);
        assert(d.f() == 142); // works
    }
    {
        I i = createIFromCPP('D', 100);
        //assert(i.f() == 142); // fails, because i.f() returns 122
    }
    {
        B b = createBFromCPP('D', 100);
        //assert(b.f() == 142); // Segmentation fault
    }
    {
        D d = createDFromCPP(100);
        //assert(d.f() == 142); // Segmentation fault
    }
    runCPPTests();
}

//////////////// test.cpp ////////////////

#include <assert.h>

class A
{
public:
    A(int i);
    virtual ~A();

    int i;
};

class I
{
public:
    virtual int f() const = 0;
};

class B : public A, public I
{
public:
    B(int i);
    virtual int f() const;
};

class D : public B
{
public:
    D(int i);
    virtual int f() const;
};

A::A(int i) : i(i)
{
}

A::~A()
{
}

B::B(int i) : A(i)
{
}

int B::f() const
{
    return i + 22;
}

I *createIFromCPP(char type, int i)
{
    switch (type)
    {
    case 'B':
        return new B(i);
    case 'D':
        return new D(i);
    default:
        return 0;
    }
}

B *createBFromCPP(char type, int i)
{
    switch (type)
    {
    case 'B':
        return new B(i);
    case 'D':
        return new D(i);
    default:
        return 0;
    }
}

D *createDFromCPP(int i)
{
    D *d = new D(i);
    return d;
}

I *createIFromD(char type, int i);
B *createBFromD(char type, int i);
D *createDFromD(int i);

void runCPPTests()
{
    {
        D *d = new D(100);
        assert(d->f() == 142); // Segmentation fault
    }
    {
        I *i = createIFromD('D', 100);
        assert(i->f() == 142); // fails, because i.f() returns 122
    }
    {
        B *b = createBFromD('D', 100);
        assert(b->f() == 142); // works
    }
    {
        D *d = createDFromD(100);
        assert(d->f() == 142); // works
    }
}

//////////////////////////////////////////

The issue exists under Linux and Windows. The comments describe the behaviour
under Linux x86_64. Sometimes the call results in a crash. Other times it seems
to call the function of a parent class. Some calls also work as expected.

If the constructors are removed and A.i is set after creating the object, it
works as expected.

--
Sep 18