www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Access violation when calling C DLL from D

reply AnoHito <anohito isans.net> writes:
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
next sibling parent reply BBasile <bb.temp gmx.com> writes:
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
parent reply AnoHito <anohito isans.net> writes:
On Monday, 2 November 2015 at 02:13:29 UTC, BBasile wrote:
 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
I did, but it just produced a ton of errors...
Nov 01 2015
parent reply Atila Neves <atila.neves gmail.com> writes:
On Monday, 2 November 2015 at 02:30:09 UTC, AnoHito wrote:
 On Monday, 2 November 2015 at 02:13:29 UTC, BBasile wrote:
 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
I did, but it just produced a ton of errors...
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 Atila
Nov 02 2015
parent reply AnoHito <anohito isans.net> writes:
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

 Atila
I 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) # define MRB_API __declspec(dllexport) #else # define MRB_API __declspec(dllimport) #endif #else # define MRB_API extern #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
parent AnoHito <anohito isans.net> writes:
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
prev sibling parent Nicholas Wilson <iamthewilsonator hotmail.com> writes:
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 pointer
 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.
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