www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - instance of sub class created in a dll has wired behaviour when cast

reply "liyu" <yunwind msn.com> writes:
I am not sure it's a bug of tango or dmd, so i post it here. The example 
code as below

//file common
module common;

abstract class DummyA {

}

abstract class DummyB : DummyA {

}

abstract class Factory {
	DummyB createDummy();
}

//file dll
module mydll;

import common;

import tango.sys.win32.Types;

import tango.io.Stdout;
import tango.stdc.stdio;

// The core DLL init code.
extern (C) bool  rt_init( void delegate( Exception ) dg = null );
extern (C) bool  rt_term( void delegate( Exception ) dg = null );

HINSTANCE g_hInst;

extern (Windows)
BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved)
{
    switch (ulReason)
    {
	case DLL_PROCESS_ATTACH:
		rt_init();
	    break;

	case DLL_PROCESS_DETACH:
		tango.stdc.stdio._fcloseallp = null;
		rt_term();
	    break;

	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
	    // Multiple threads not supported yet
	    return false;
    }
    g_hInst=hInstance;
    return true;
}

class DummyC : DummyB {

}

class DllFactory : Factory {
	override DummyC createDummy() {
		return new DummyC;	} 

}

export extern(C) DllFactory create() {
	return new DllFactory;}

//file test
module test;

import common;

import tango.sys.SharedLib;
import tango.util.log.Trace;

// declaring our function pointer
typedef extern (C) Factory function() createFunc;
createFunc dllcreate;

void main() {
    if (auto lib = SharedLib.load(`mydll.dll`)) {
        Trace.formatln("Library successfully loaded");

        void* ptr = lib.getSymbol("create");
        if (ptr) {
            Trace.formatln("Symbol dllprint found. Address = 0x{:x}", ptr);

            // binding function address from DLL to our function pointer
            void **point = cast(void **)&dllcreate;
            *point = ptr;

            // using our function
            auto factory = dllcreate();
            auto dummy = factory.createDummy();

            Trace.formatln(dummy.classinfo.name);
            auto d2 = cast(DummyB)dummy;
            assert(d2 !is null); //ok

            DummyA a = dummy;
            Trace.formatln(a.classinfo.name);
            auto d3 = cast(DummyB)a;
            assert(d3 !is null);    //Assertion failure

        } else {
            Trace.formatln("Symbol dllprint not found");
        }

        lib.unload();
    } else {
        Trace.formatln("Could not load the library");
    }

    assert (0 == SharedLib.numLoadedLibs);
}

The result is:
Library successfully loaded
Symbol dllprint found. Address = 0x1000308c
mydll.DummyC
mydll.DummyC
tango.core.Exception.AssertException test(35): Assertion failure

As you see, var a is a instance of DummyC which is a subclass of DummyB, but 
the cast is failure.
 
Mar 22 2009
next sibling parent reply Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
2009/3/22 liyu <yunwind msn.com>:
 I am not sure it's a bug of tango or dmd, so i post it here. The example
 code as below

 ...

 The result is:
 Library successfully loaded
 Symbol dllprint found. Address = 0x1000308c
 mydll.DummyC
 mydll.DummyC
 tango.core.Exception.AssertException test(35): Assertion failure

 As you see, var a is a instance of DummyC which is a subclass of DummyB, but
 the cast is failure.

This is, unfortunately, a limitation imposed by Windows DLLs. DLLs cannot, by their nature, load symbols out of the host application that loads them. As a result, the typeinfo of classes is duplicated, one copy in the host and one in each DLL. Thus you end up with classes which _look_ the same, but casting them will inevitably fail. There is no real robust solution while still using DLLs, and the problem only exists on Windows. DDL attempts (and succeeds, quite nicely) in performing manual dynamic linking. http://www.dsource.org/projects/ddl
Mar 22 2009
parent "liyu" <yunwind msn.com> writes:
"Jarrett Billingsley" <jarrett.billingsley gmail.com> wrote in message 
news:mailman.986.1237779483.22690.digitalmars-d puremagic.com...
 2009/3/22 liyu <yunwind msn.com>:
 I am not sure it's a bug of tango or dmd, so i post it here. The example
 code as below

 ...

 The result is:
 Library successfully loaded
 Symbol dllprint found. Address = 0x1000308c
 mydll.DummyC
 mydll.DummyC
 tango.core.Exception.AssertException test(35): Assertion failure

 As you see, var a is a instance of DummyC which is a subclass of DummyB, 
 but
 the cast is failure.

This is, unfortunately, a limitation imposed by Windows DLLs. DLLs cannot, by their nature, load symbols out of the host application that loads them. As a result, the typeinfo of classes is duplicated, one copy in the host and one in each DLL. Thus you end up with classes which _look_ the same, but casting them will inevitably fail. There is no real robust solution while still using DLLs, and the problem only exists on Windows. DDL attempts (and succeeds, quite nicely) in performing manual dynamic linking. http://www.dsource.org/projects/ddl

wow, I never known that before, thanks!
Mar 22 2009
prev sibling parent davidl <davidl 126.com> writes:
在 Mon, 23 Mar 2009 11:37:56 +0800,Jarrett Billingsley  
<jarrett.billingsley gmail.com> 写道:

 2009/3/22 liyu <yunwind msn.com>:
 I am not sure it's a bug of tango or dmd, so i post it here. The example
 code as below

 ...

 The result is:
 Library successfully loaded
 Symbol dllprint found. Address = 0x1000308c
 mydll.DummyC
 mydll.DummyC
 tango.core.Exception.AssertException test(35): Assertion failure

 As you see, var a is a instance of DummyC which is a subclass of  
 DummyB, but
 the cast is failure.

This is, unfortunately, a limitation imposed by Windows DLLs. DLLs cannot, by their nature, load symbols out of the host application that loads them. As a result, the typeinfo of classes is duplicated, one copy in the host and one in each DLL. Thus you end up with classes which _look_ the same, but casting them will inevitably fail. There is no real robust solution while still using DLLs, and the problem only exists on Windows. DDL attempts (and succeeds, quite nicely) in performing manual dynamic linking. http://www.dsource.org/projects/ddl

I think if the runtime typeinfo is modularized to a seperated dll, the problem should go away. Just on one think that's a must at the moment.
Mar 22 2009