www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Binding to C - Arrays and Access Violation

reply jmh530 <john.michael.hall gmail.com> writes:
I'm working on generating a binding to a C library. I've got the 
.h file converted and can call some parts of the library with no 
errors. However, I have reached a stumbling block in a critical 
part.

The library requires passing function pointers to various 
functions in the library. When I try to run these functions, I 
get an Access Violation error. I enabled additional DMD warnings, 
which helped pinpoint the issue.

My D code calls a C function. One of the parameters to the C 
function is a function pointer to a D function. This D function 
(below) is one that I copied  from the C library's tutorial. I 
only slightly changed the signature. This function is eventually 
called in other functions in the C library.

double myfunc(uint n, const double* x, double* grad, void* 
my_func_data)
{
     if (grad)
     {
         grad[0] = 0.0;
         grad[1] = 0.5 / sqrt(x[1]);
     }
     return sqrt(x[1]);
}

The line (though likely the next will too) that causes a problem 
is

grad[0] = 0.0;

Thus, as it is an Access Violation, I'm guessing the issue is 
with accessing elements of arrays in the D function from the C 
function. I don't know. When I try to call the D function in D, 
it works, but I have to refer to x and grad as x.ptr and grad.ptr.

I'm not sure how to go about fixing this...
Feb 02 2016
next sibling parent reply biozic <dransic gmail.com> writes:
On Tuesday, 2 February 2016 at 22:56:28 UTC, jmh530 wrote:
 I'm working on generating a binding to a C library. I've got 
 the .h file converted and can call some parts of the library 
 with no errors. However, I have reached a stumbling block in a 
 critical part.

 The library requires passing function pointers to various 
 functions in the library. When I try to run these functions, I 
 get an Access Violation error. I enabled additional DMD 
 warnings, which helped pinpoint the issue.

 My D code calls a C function. One of the parameters to the C 
 function is a function pointer to a D function. This D function 
 (below) is one that I copied  from the C library's tutorial. I 
 only slightly changed the signature. This function is 
 eventually called in other functions in the C library.

 double myfunc(uint n, const double* x, double* grad, void* 
 my_func_data)
 {
     if (grad)
     {
         grad[0] = 0.0;
         grad[1] = 0.5 / sqrt(x[1]);
     }
     return sqrt(x[1]);
 }

 The line (though likely the next will too) that causes a 
 problem is

 grad[0] = 0.0;

 Thus, as it is an Access Violation, I'm guessing the issue is 
 with accessing elements of arrays in the D function from the C 
 function. I don't know. When I try to call the D function in D, 
 it works, but I have to refer to x and grad as x.ptr and 
 grad.ptr.

 I'm not sure how to go about fixing this...
Is grad allocated in the D code? If so, it could have been collected because the GC lost track of its use when passing to and from the C code. Or is grad owned by the C code? If so, either there is a bug in the library or it's misused, because its memory has been freed/has never been allocated/has gone out of scope.
Feb 02 2016
parent jmh530 <john.michael.hall gmail.com> writes:
On Wednesday, 3 February 2016 at 00:28:24 UTC, biozic wrote:
 Is grad allocated in the D code? If so, it could have been 
 collected because the GC lost track of its use when passing to 
 and from the C code. Or is grad owned by the C code? If so, 
 either there is a bug in the library or it's misused, because 
 its memory has been freed/has never been allocated/has gone out 
 of scope.
grad is only created in the C code. I don't pass it myself.
Feb 02 2016
prev sibling parent reply Mike Parker <aldacron gmail.com> writes:
On Tuesday, 2 February 2016 at 22:56:28 UTC, jmh530 wrote:

 My D code calls a C function. One of the parameters to the C 
 function is a function pointer to a D function. This D function 
 (below) is one that I copied  from the C library's tutorial. I 
 only slightly changed the signature. This function is 
 eventually called in other functions in the C library.

 double myfunc(uint n, const double* x, double* grad, void* 
 my_func_data)
 Thus, as it is an Access Violation, I'm guessing the issue is 
 with accessing elements of arrays in the D function from the C 
 function. I don't know. When I try to call the D function in D, 
 it works, but I have to refer to x and grad as x.ptr and 
 grad.ptr.

 I'm not sure how to go about fixing this...
The parameter to the C function should be declared as extern(C), and so should your function implementation. extern(C) alias FuncPtr = double function(uint, const(double)*, double*, void*); extern(C) void takeFuncPtr(FuncPtr); extern(C) double myfunc(uint n, const(double)* x, double* grad, void* my_func_data) { ... } If you haven't done that, then this is quite possibly the root of your problem.
Feb 02 2016
parent reply jmh530 <john.michael.hall gmail.com> writes:
On Wednesday, 3 February 2016 at 00:37:25 UTC, Mike Parker wrote:
 The parameter to the C function should be declared as 
 extern(C), and so should your function implementation.

 extern(C) alias FuncPtr = double function(uint, const(double)*, 
 double*, void*);
 extern(C) void takeFuncPtr(FuncPtr);

 extern(C) double myfunc(uint n, const(double)* x, double* grad, 
 void* my_func_data) {
 ...
 }

 If you haven't done that, then this is quite possibly the root 
 of your problem.
Success! Couldn't have done it without your help. I had originally had the equivalent of FuncPtr as extern(C), but I had removed that because myfunc wouldn't compile. I hadn't thought of putting those modifications on myfunc. Just assumed that I did the function pointers wrong. A few extra questions: 1) In other parts of the code I'm using extern(System), but that doesn't work for these. Why is extern(C) used for function pointers?, 2) You use const(double)*, in other parts of the code I had converted the C code from const char* to const(char*). Does it matter where the pointer * falls?
Feb 02 2016
parent Mike Parker <aldacron gmail.com> writes:
On Wednesday, 3 February 2016 at 04:19:37 UTC, jmh530 wrote:

 A few extra questions: 1) In other parts of the code I'm using 
 extern(System), but that doesn't work for these. Why is 
 extern(C) used for function pointers?,
extern(C) is only used with function pointers when it's needed. It depends entirely on how the C library was compiled. By default, most compilers compile with the cdecl calling convention, which is what extern(C) specifies in D code. Windows system libraries are usually compiled to use the stdcall calling convention. The D equivalent is extern(Windows). extern(System) translates to extern(Windows) on Windows and extern(C) elsewhere. Function pointers passed to C code need to have the same calling convention as that of the library to which they are passed.
 2) You use const(double)*, in other parts of the code I had 
 converted the C code from const char* to const(char*). Does it 
 matter where the pointer * falls?
Technically, const(char)* is a mutable pointer to const data and const(char*) is an immutable pointer to const data.
Feb 03 2016