www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Segmentation fault while creating a class object by dlsym-ed function

reply "Konstantin J. Chernov" <kjchernov commander.pp.ru> writes:
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);
}
Jul 17 2012
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2012-07-18 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).

Classes are always references.
 What am I doing wrong here? Is there any way to do what I'm trying to do
 right way?

Dynamic libraries aren't properly supported by the runtime. -- /Jacob Carlborg
Jul 17 2012
parent Jacob Carlborg <doob me.com> writes:
On 2012-07-18 10:17, Konstantin J. Chernov wrote:
 What am I doing wrong here? Is there any way to do what I'm trying to do
 right way?

Dynamic libraries aren't properly supported by the runtime.

That's terrible:( It's so nice to make an interface, and create classes that inherit this interface dynamically, without linking... Maybe there's another way?

No, not that I can think of for now. But it's a known problem that is being worked on: https://github.com/dawgfoto/druntime/tree/SharedRuntime -- /Jacob Carlborg
Jul 18 2012
prev sibling next sibling parent "Konstantin J. Chernov" <kjchernov commander.pp.ru> writes:
 What am I doing wrong here? Is there any way to do what I'm 
 trying to do
 right way?

Dynamic libraries aren't properly supported by the runtime.

That's terrible:( It's so nice to make an interface, and create classes that inherit this interface dynamically, without linking... Maybe there's another way?
Jul 18 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Konstantin J. Chernov:

 testclass.di:

 class testclass
 {
     this(const wstring loadmsg);
     ~this();
     wstring foo();
 };

And usually you don't need to write .di files in D. Bye, bearophile
Jul 18 2012
prev sibling next sibling parent reply =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= <alex lycus.org> writes:
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 lycus.org http://lycus.org
Jul 18 2012
parent Alexandr Druzhinin <drug2004 bk.ru> writes:
Probably you mean the same problem that is described in the thread 
avobe, see "using GC needs particular skills?"

Every time after execution my code I got very frustating access 
violation and the problem was misunderstanding garbage collector because 
I've never used it before.
Jul 18 2012
prev sibling parent "Konstantin J. Chernov" <kjchernov commander.pp.ru> writes:
Thank you for your replies!

I've found a working solution - all I needed is to change wstring 
to const wstring, and pass it not as func("something"), but as

   wstring tmp = "something"; func(tmp);

That's really odd, because I don't understand, how those changes 
made segfault disappear.

Here's the working code:

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(const wstring) a;
     a = cast(testclass function(const wstring))dlsym(handle, 
"loadClass");
     wstring tmp = "Test";
     testclass b = a(tmp);
     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);
}


dmd test.d -L-ldl
dmd testclass.d -fPIC -shared
Jul 18 2012