digitalmars.D.learn - Access violation when calling C DLL from D
- AnoHito (50/50) Nov 01 2015 Hi, I am trying to write a simple interface to the MRuby Ruby
- BBasile (3/7) Nov 01 2015 You can give a try at h2d, the C header to D interface converter:
- AnoHito (2/10) Nov 01 2015 I did, but it just produced a ton of errors...
- Atila Neves (6/18) Nov 02 2015 Try this instead:
- Nicholas Wilson (18/68) Nov 02 2015 In D the unary * is left associative NOT right. i.e. write int*
Hi, I am trying to write a simple interface to the MRuby Ruby interpreter so I can use ruby scripts in my D program. I was able to get MRuby compiled as a DLL without too much difficulty, but the headers are very long and complicated, and porting them entirely to D would be a huge project in and of itself. I am trying to get by with only what I need, so here is what I have so far: module script.mruby; alias mrb_bool = bool; alias mrb_int = int; alias mrb_float = double; alias mrb_sym = uint; alias mrb_aspec = uint; struct mrb_value { } struct RObject { } struct RClass { } struct mrb_value { } struct mrb_state { } extern(C) char *mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr); extern (C) mrb_value mrb_load_string(mrb_state *mrb, const char *s); extern (C) mrb_value mrb_load_nstring(mrb_state *mrb, const char *s, int len); extern (C) mrb_state *mrb_open(); extern (C) void mrb_close(mrb_state *mrb); In theory, this should be enough to test that MRuby is working, so I tried to run the following code: mrb = mrb_open(); mrb_value result = mrb_load_string(mrb, toStringz("String('test')")); Log.info(to!string(mrb_string_value_cstr(mrb, &result))); But the result was: object.Error (0): Access Violation I wasn't able to get the Visual D debugger to trace into the code, but after some investigation, I figured out that the error was occurring in the strlen runtime function. I don't think I did anything wrong with the way I passed a string into the mrb_load_string function, so I am kind of at a loss as to what the problem might be.
Nov 01 2015
On Monday, 2 November 2015 at 01:02:45 UTC, AnoHito wrote:[...] the headers are very long and complicated, and porting them entirely to D would be a huge project in and of itself. [...]You can give a try at h2d, the C header to D interface converter: http://dlang.org/htod.html
Nov 01 2015
On Monday, 2 November 2015 at 02:13:29 UTC, BBasile wrote:On Monday, 2 November 2015 at 01:02:45 UTC, AnoHito wrote:I did, but it just produced a ton of errors...[...] the headers are very long and complicated, and porting them entirely to D would be a huge project in and of itself. [...]You can give a try at h2d, the C header to D interface converter: http://dlang.org/htod.html
Nov 01 2015
On Monday, 2 November 2015 at 02:30:09 UTC, AnoHito wrote:On Monday, 2 November 2015 at 02:13:29 UTC, BBasile wrote:Try this instead: https://github.com/jacob-carlborg/dstep It's been used to convert C Ruby declarations to D: https://github.com/jacob-carlborg/orbit/tree/master/ruby AtilaOn Monday, 2 November 2015 at 01:02:45 UTC, AnoHito wrote:I did, but it just produced a ton of errors...[...] the headers are very long and complicated, and porting them entirely to D would be a huge project in and of itself. [...]You can give a try at h2d, the C header to D interface converter: http://dlang.org/htod.html
Nov 02 2015
On Monday, 2 November 2015 at 15:56:20 UTC, Atila Neves wrote:Try this instead: https://github.com/jacob-carlborg/dstep It's been used to convert C Ruby declarations to D: https://github.com/jacob-carlborg/orbit/tree/master/ruby AtilaI might try it later, but I don't think the header conversion is the problem in this case. I tried to get some insight into what was happening by modifying the mrb_load_nstring function: MRB_API mrb_value mrb_load_nstring(mrb_state *mrb, const char *s, int len) { FILE *f = fopen("output.txt", "w"); fprintf(f, "mrb: %p, s: %p, len: %i\n", mrb, s, len); fclose(f); return mrb_load_nstring_cxt(mrb, s, len, NULL); } The output was: mrb: 0052E818, s: 0000000E, len: 5 That was... odd. I tried to modify my extern statement a bit: extern (C) mrb_value mrb_load_nstring(void *junk, mrb_state *mrb, const char *s, int len); And ran the following code: mrb = mrb_open(); mrb_value result = mrb_load_nstring(cast(void *) 0, mrb, toStringz("String('test')"), 14); Log.info(to!string(mrb_string_value_cstr(mrb, &result))); This time the result was: mrb: 0039E750, s: 0052E818, len: 14 Things actually got a little further now that the values were getting passed correctly(?) but another null pointer access violation got triggered later on in the code. So something weird is definitely going on here. Is there something that needs to be done differently to handle the calling conventions here? I think all the functions in MRuby that I have attempted to call so far are regular cdecl functions. Here is the definitions of MRB_API from the original header, in case it sheds any light on things: #if defined(MRB_BUILD_AS_DLL) #if defined(MRB_CORE) || defined(MRB_LIB) #else #endif #else #endif Could the problem be because I used mingw to build the DLL, and Visual D to build my main project? It was more or less necessary, since Visual Studio's build tools couldn't handle the MRuby build scripts. I didn't think it should cause any problems, but maybe I was wrong. Also, here is the command I used to generate the lib for the DLL: implib /s mruby.lib mruby.dll Is implib still the best tool for doing this? The only version I was able to find was very old, so maybe it is not generating the lib files correctly.
Nov 02 2015
Okay, I finally got it working. The problem was that mrb_value needed to be fully defined in order for my code to work, because it was being passed on the stack directly instead of by a pointer: struct mrb_value { union { mrb_float f; void* p; mrb_int i; mrb_sym sym; } mrb_vtype tt; }
Nov 02 2015
On Monday, 2 November 2015 at 01:02:45 UTC, AnoHito wrote:Hi, I am trying to write a simple interface to the MRuby Ruby interpreter so I can use ruby scripts in my D program. I was able to get MRuby compiled as a DLL without too much difficulty, but the headers are very long and complicated, and porting them entirely to D would be a huge project in and of itself. I am trying to get by with only what I need, so here is what I have so far: module script.mruby; alias mrb_bool = bool; alias mrb_int = int; alias mrb_float = double; alias mrb_sym = uint; alias mrb_aspec = uint; struct mrb_value { } struct RObject { } struct RClass { } struct mrb_value { } struct mrb_state { } extern(C) char *mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr); extern (C) mrb_value mrb_load_string(mrb_state *mrb, const char *s); extern (C) mrb_value mrb_load_nstring(mrb_state *mrb, const char *s, int len); extern (C) mrb_state *mrb_open(); extern (C) void mrb_close(mrb_state *mrb);In D the unary * is left associative NOT right. i.e. write int* a,b,c; // a,b and c are all int* NOT int*, int,int as would be the case in C because you are not allowed to change the type during the declaration.In theory, this should be enough to test that MRuby is working, so I tried to run the following code: mrb = mrb_open(); mrb_value result = mrb_load_string(mrb, toStringz("String('test')"));string literals are automatically null terminated, no need to `toStringz`. if it was not a literal the you would have to.Log.info(to!string(mrb_string_value_cstr(mrb, &result))); But the result was: object.Error (0): Access Violation(0) suggests a null pointerI wasn't able to get the Visual D debugger to trace into the code, but after some investigation, I figured out that the error was occurring in the strlen runtime function. I don't think I did anything wrong with the way I passed a string into the mrb_load_string function, so I am kind of at a loss as to what the problem might be.and the only operation here likely to call strlen is to!string from a char* (since D strings know their length) perhaps you should inspect the value returned from mrb_string_value_cstr few possible places to look alignment - are the types declared in c declared with an alignment? check the values of mob and result Also take a Look at DStep on github for auto translation of C
Nov 02 2015