www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Shared library string safety?

reply "Mineko" <uminekorox gmail.com> writes:
Alright, so I FINALLY got shared libraries somewhat working 
through my program, however I have some issues transferring data 
between the shared library and the main program, the problem is 
between 
https://github.com/MinekoRox/Breaker-Engine/blob/master/src/breake
/utility/settings.d 
and 
https://github.com/MinekoRox/Breaker-Engine/blob/master/res/scripts/core/settings.d

The settings script is loaded by 
https://github.com/MinekoRox/Breaker-Engine/blob/master/src/breaker/utility/core.d

And, this is the error I get:
+start(string[])
Starting up the program
800600 ����B
Shutting off the program
Writing logs to disk
ERROR: Error(s) occured, check the error log
-start(string[])
+stop()
Segmentation fault (core dumped)

The 800600 is width and height, the problem is the binary output 
of what's supposed to be a string.
Jan 13 2014
parent reply "evilrat" <evilrat666 gmail.com> writes:
On Tuesday, 14 January 2014 at 05:50:37 UTC, Mineko wrote:
 Alright, so I FINALLY got shared libraries somewhat working 
 through my program, however I have some issues transferring 
 data between the shared library and the main program, the 
 problem is between 
 https://github.com/MinekoRox/Breaker-Engine/blob/master/src/breake
/utility/settings.d 
 and 
 https://github.com/MinekoRox/Breaker-Engine/blob/master/res/scripts/core/settings.d

 The settings script is loaded by 
 https://github.com/MinekoRox/Breaker-Engine/blob/master/src/breaker/utility/core.d

 And, this is the error I get:
 +start(string[])
 Starting up the program
 800600 ����B
 Shutting off the program
 Writing logs to disk
 ERROR: Error(s) occured, check the error log
 -start(string[])
 +stop()
 Segmentation fault (core dumped)

 The 800600 is width and height, the problem is the binary 
 output of what's supposed to be a string.
are you set your gc proxies for shared libs, right? if not, i think it would be safer to do string.dup(as with other arrays) when moving them between shared lib boundaries. but still keep in mind that current GC may not handle properly multiple intances. p.s. i don't do shared libs for non-Windows platform for a long time now, so it may be outdated info for now...
Jan 13 2014
parent reply "Mineko" <uminekorox gmail.com> writes:
On Tuesday, 14 January 2014 at 06:40:52 UTC, evilrat wrote:
 On Tuesday, 14 January 2014 at 05:50:37 UTC, Mineko wrote:
 Alright, so I FINALLY got shared libraries somewhat working 
 through my program, however I have some issues transferring 
 data between the shared library and the main program, the 
 problem is between 
 https://github.com/MinekoRox/Breaker-Engine/blob/master/src/breake
/utility/settings.d 
 and 
 https://github.com/MinekoRox/Breaker-Engine/blob/master/res/scripts/core/settings.d

 The settings script is loaded by 
 https://github.com/MinekoRox/Breaker-Engine/blob/master/src/breaker/utility/core.d

 And, this is the error I get:
 +start(string[])
 Starting up the program
 800600 ����B
 Shutting off the program
 Writing logs to disk
 ERROR: Error(s) occured, check the error log
 -start(string[])
 +stop()
 Segmentation fault (core dumped)

 The 800600 is width and height, the problem is the binary 
 output of what's supposed to be a string.
are you set your gc proxies for shared libs, right? if not, i think it would be safer to do string.dup(as with other arrays) when moving them between shared lib boundaries. but still keep in mind that current GC may not handle properly multiple intances. p.s. i don't do shared libs for non-Windows platform for a long time now, so it may be outdated info for now...
Wow, um, that actually worked, thank you.
Jan 13 2014
parent reply "Mineko" <uminekorox gmail.com> writes:
Sorry for the double post, I should be more specific.
.dup worked, I don't know how to have the GC proxy for shared 
libs though.
Jan 13 2014
parent reply "evilrat" <evilrat666 gmail.com> writes:
On Tuesday, 14 January 2014 at 06:48:48 UTC, Mineko wrote:
 Sorry for the double post, I should be more specific.
 .dup worked, I don't know how to have the GC proxy for shared 
 libs though.
the reason string.dup worked is due to GC on app side, right after the moment your lib receive the original string it is may be marked by GC for collection, so you need to save a copy on lib side. but using the proxies it should work without copying. for windows here is the topic about this http://dlang.org/dll.html for *nix platforms it should be the same. in short(pseudocode): ========================== app.d extern(C) void* gc_getProxy(); void main() { loadlib(); initLib( gc_getProxy() ); ... do something ... libFinalize(); } ------------------ lib.d extern (C) { void gc_setProxy(void* p); void gc_clrProxy(); } export void initLib(void* gc) { gc_setProxy(gc); } export void libFinalize() { gc_clrProxy(); } ========================== as i said i don't know about current status of shared libs, but there was some progress on linux and Windows, and unfortunatelly not OS X...
Jan 13 2014
parent reply "Mineko" <uminekorox gmail.com> writes:
On Tuesday, 14 January 2014 at 07:23:52 UTC, evilrat wrote:
 the reason string.dup worked is due to GC on app side, right 
 after the moment your lib receive the original string it is may 
 be marked by GC for collection, so you need to save a copy on 
 lib side. but using the proxies it should work without copying.


 for windows here is the topic about this 
 http://dlang.org/dll.html

 for *nix platforms it should be the same.

 in short(pseudocode):
 ==========================
 app.d

 extern(C) void* gc_getProxy();

 void main()
 {
   loadlib();
   initLib( gc_getProxy() );
   ... do something ...
   libFinalize();
 }

 ------------------
 lib.d

 extern (C)
 {
     void  gc_setProxy(void* p);
     void  gc_clrProxy();
 }

 export void initLib(void* gc)
 {
     gc_setProxy(gc);
 }

 export void libFinalize()
 {
     gc_clrProxy();
 }
 ==========================

 as i said i don't know about current status of shared libs, but 
 there was some progress on linux and Windows, and 
 unfortunatelly not OS X...
I see, I'll have to look more into that, on a slightly unrelated note, any idea what's going on with glfwCreateWindow, it keeps wanting to be null while it's supposed to be an adddress. this.get = glfwCreateWindow(settings.width, settings.height, toStringz(settings.title), this.monitor, this.share); writeln(this.get); That writeln will give me null, is it related to all this stuff?
Jan 13 2014
next sibling parent "evilrat" <evilrat666 gmail.com> writes:
On Tuesday, 14 January 2014 at 07:44:21 UTC, Mineko wrote:
 I see, I'll have to look more into that, on a slightly 
 unrelated note, any idea what's going on with glfwCreateWindow, 
 it keeps wanting to be null while it's supposed to be an 
 adddress.

 this.get = glfwCreateWindow(settings.width, settings.height,
 	toStringz(settings.title), this.monitor, this.share);
 			
 writeln(this.get);

 That writeln will give me null, is it related to all this stuff?
are you using derelict for this? do you really need fullscreen and sharing contexts? try to call this to get non-fullscreen window without sharing (just peronal, but also it may be a bit more readeble using UFCS on toStringz) this.get = glfwCreateWindow(settings.width, settings.height, settings.title.toStringz(), null, null); if that work for you then problem is due to sharing which may require context(which you probably don't have or trying to share with itself), or due to driver issues related to fullscreen mode if on linux, but i'm unsure about the later.
Jan 14 2014
prev sibling next sibling parent "TheFlyingFiddle" <theflyingfiddle gmail.com> writes:
On Tuesday, 14 January 2014 at 07:44:21 UTC, Mineko wrote:
 I see, I'll have to look more into that, on a slightly 
 unrelated note, any idea what's going on with glfwCreateWindow, 
 it keeps wanting to be null while it's supposed to be an 
 adddress.

 this.get = glfwCreateWindow(settings.width, settings.height,
 	toStringz(settings.title), this.monitor, this.share);
 			
 writeln(this.get);
glfwCreateWindow returns a null ptr if something is wrong with it's parameters or os driver or anything it can detect really. To get error information you can use glfwSetErrorCallback with a custom function and handle the errors with it. Something like this: extern(C) void errorFunc(int error_code, const(char)* errorMessage) { //Do something here like wrilteln. } void main() { //Load libs and setup stuff. glfwSetErrorCallback(&errorFunc); //Now anything that gives an error will forward it to //errorFunc. }
 That writeln will give me null, is it related to all this stuff?
I doubt it.
Jan 14 2014
prev sibling parent reply "evilrat" <evilrat666 gmail.com> writes:
On Tuesday, 14 January 2014 at 07:44:21 UTC, Mineko wrote:
 this.get = glfwCreateWindow(settings.width, settings.height,
 	toStringz(settings.title), this.monitor, this.share);
 			
 writeln(this.get);

 That writeln will give me null, is it related to all this stuff?
i've looked up in your sources on github and not found derelict initiliazation. i recommend loading glfw in relevant module with module ctor. most if non all derelict bindings has dynamic loading, don't forget to load and init derelict 'plugins' if necessary. ---------------- module window; static this() { DerelictGLFW.load(); } class Window { ... using GLFW here ... } --------------
Jan 14 2014
parent reply "Mineko" <uminekorox gmail.com> writes:
On Tuesday, 14 January 2014 at 09:35:11 UTC, evilrat wrote:
 On Tuesday, 14 January 2014 at 07:44:21 UTC, Mineko wrote:
 this.get = glfwCreateWindow(settings.width, settings.height,
 	toStringz(settings.title), this.monitor, this.share);
 			
 writeln(this.get);

 That writeln will give me null, is it related to all this 
 stuff?
i've looked up in your sources on github and not found derelict initiliazation. i recommend loading glfw in relevant module with module ctor. most if non all derelict bindings has dynamic loading, don't forget to load and init derelict 'plugins' if necessary. ---------------- module window; static this() { DerelictGLFW.load(); } class Window { ... using GLFW here ... } --------------
I'm pretty sure it's initialized here: https://github.com/MinekoRox/Breaker-Engine/blob/master/src/breaker/utility/belt.d /** Initialize GLFW */ auto initGLFW() { import breaker.main : timer; DerelictGLFW3.load; if (!glfwInit) return false; timer.time = 0.0001; return true; } Perhaps I should be using () with GLFW3.load and glfwInit? I'll try a static loading though, sure.
Jan 14 2014
parent reply Mike Parker <aldacron gmail.com> writes:
On 1/14/2014 9:10 PM, Mineko wrote:

 Perhaps I should be using () with GLFW3.load and glfwInit?
Yes, please do this. For DerelictGLFW3.load, it's just a matter of style and doesn't make a difference. However, glfwInit is a *function pointer*, not a function.. So what you're effectively doing there is testing if the function pointer is null or not. You aren't actually calling the function. Since you already called DerelictGLFW3.load, then it obviously isn't null, so your method completes and returns true. Then later, when you call glfwCreateWindow, since the library was never initialized, it returns null. You could have saved yourself a lot of time by using an error callback as recommended earlier in this thread. And you should set the callback between DerelictGLFW3.load and glfwInit. extern(C) nothrow void onErr(int code, const(char)* msg) { // log the message, but be aware that you may need to wrap // it in a try...catch block, since the callback has to be // nothrow. } auto initGLFW() { import breaker.main : timer; DerelictGLFW3.load; glfwSetErrorCallback( &onErr ); // Add the parens here!!!!!!!! if ( !glfwInit() ) return false; timer.time = 0.0001; return true; } Do this and you'll get an error message if any glfw function call fails. And always keep in mind that when using Derelict, the library functions you call are all function pointers. That means this function: auto glfwTerm() {return glfwTerminate;} Is returning a function pointer. It isn't calling anything. You need to add parens here, too. In fact, I strongly recommend you use parens everywhere unless you are calling properties. Speaking of which, why would you make glfwTerm a property? One more bit of advice. In initGL, you have this: DerelictGL3.load; glfwMakeContextCurrent(window.get); DerelictGL3.reload; The call to glfwMakeContextCurrent doesn't need to be there. For ease of maintenance, I suggest you move it to the method where you call glfwCreateWindow. That way, initGL does not depend on the window already being created. You don't need to load DerelictGL3 before calling it.
 I'll try a static loading though, sure.
This won't make a difference.
Jan 14 2014
parent reply Mike Parker <aldacron gmail.com> writes:
On 1/14/2014 9:55 PM, Mike Parker wrote:


 That way, initGL does not depend on the window already
 being created.
Actually, scratch that. DerelictGL3.reload does depend on the context already being created. However, the call to glfwMakeContextCurrent still should be in the same spot you create the window.
Jan 14 2014
parent "Mineko" <uminekorox gmail.com> writes:
On Tuesday, 14 January 2014 at 12:58:04 UTC, Mike Parker wrote:
 On 1/14/2014 9:55 PM, Mike Parker wrote:


 That way, initGL does not depend on the window already
 being created.
Actually, scratch that. DerelictGL3.reload does depend on the context already being created. However, the call to glfwMakeContextCurrent still should be in the same spot you create the window.
Ahhh thank you, I'm currently away from my computer so I couldn't do much as far as my code goes, but I'll certainly do all of that, I always have trouble with functions and function pointers haha. :P
Jan 14 2014