Segmentation fault while creating a class object by dlsym-ed function

Alex Rønne Petersen alex at lycus.org
Wed Jul 18 03:38:03 PDT 2012


On 18-07-2012 06:51, Konstantin J. Chernov wrote:
> Hello. When I'm trying to create a class object by using a dlsym-ed
> function, I'm getting a segmentation fault after execution of program.
>
> However, if I'm deleting that object before 'return 0' in main (by using
> 'delete b'), everything is going fine.
>
> I'm just started to learn D after using C++ for more than 5 years, so
> some things look really strange for me (especially that 'new
> className()' doesn't return a pointer).
>
> What am I doing wrong here? Is there any way to do what I'm trying to do
> right way?
>
> Thanks.
>
> test.d:
>
> import std.c.linux.linux;
> import std.stdio;
> import testclass;
>
> int main(string[] args)
> {
>      void* handle = dlopen("./testclass.so", RTLD_LAZY | RTLD_LOCAL);
>      testclass function(wstring) a;
>      a = cast(testclass function(wstring))dlsym(handle, "loadClass");
>      testclass b = a("test");
>      return 0;
> }
>
> testclass.di:
>
> class testclass
> {
>      this(const wstring loadmsg);
>      ~this();
>      wstring foo();
> };
>
> testclass.d:
>
> import std.stdio;
>
> class testclass
> {
>      private wstring msg;
>      this(const wstring loadmsg)
>      {
>          writeln("Class constructor");
>          this.msg = loadmsg;
>      }
>      ~this()
>      {
>      }
>      wstring foo()
>      {
>          return msg;
>      }
> };
>
> extern(C) testclass loadClass(const wstring loadmsg)
> {
>      return new testclass(loadmsg);
> }
>

As Jacob said, the D runtime isn't quite ready for shared libraries yet.

What you can do, however, is provide a bit of inversion of control to 
make the allocation happen from the runtime linked statically to your 
application:

import std.conv;

alias extern (C) void* function(size_t) Allocator;

extern (C) testclass loadClass(Allocator allocator, const wstring loadmsg)
{
     auto size = __traits(classInstanceSize, testclass);
     auto mem = allocator(size);

     return emplace!testclass(mem[0 .. size], loadmsg);
}

Then in the application:

import core.memory;
import core.sys.posix.dlfcn;
import std.stdio;
import testclass;

void* allocate(size_t size)
{
     return GC.malloc(size);
}

int main(string[] args)
{
     auto h = dlopen("./testclass.so", RTLD_LAZY | RTLD_LOCAL);
     auto a = cast(testclass function(Allocator, wstring))dlsym(h, 
"loadClass");
     auto b = a(&allocate, "test");

     return 0;
}

This should make allocation work, but I haven't actually tested it. Note 
also that even if it does work, things get more complicated when the 
class you're allocating has a finalizer, for example (see 
http://dlang.org/phobos/core_memory.html#FINALIZE).

-- 
Alex Rønne Petersen
alex at lycus.org
http://lycus.org




More information about the Digitalmars-d-learn mailing list