C# calling C++ dll (Instruction at referenced memory could not be read)

G

gwell

Hi,

I have a C# assembly that is calling directly into C++ unmanaged
code. Everything is working fine but at the very end of the process
I
get an application error, which says:

"The instruction at (hexNumber) referenced memory at (hexNumber). The
memory could not be read. Click on OK to terminate the program."

It seems to me that the .Net CLR is trying to unload the C++ dll but
hits an issue when it tries to free up some resources. I have read
that this can sometimes occur if there is a buffer overflow. For
example, if you pass in a string or array (by ref) and the C++ code
overruns the array. However, I am not sure if this is my problem.

I am passing in a number of "ref" params into the C++ function, these
are all arrays. I am passing in strings but these are "by value". I
have checked all the values going in and coming out and they all look
the exact same.

Any ideas on his would be greatly appreciated..

Thanks!
gwell
 
?

=?ISO-8859-1?Q?G=F6ran_Andersson?=

gwell said:
Hi,

I have a C# assembly that is calling directly into C++ unmanaged
code. Everything is working fine but at the very end of the process
I
get an application error, which says:

"The instruction at (hexNumber) referenced memory at (hexNumber). The
memory could not be read. Click on OK to terminate the program."

It seems to me that the .Net CLR is trying to unload the C++ dll but
hits an issue when it tries to free up some resources. I have read
that this can sometimes occur if there is a buffer overflow. For
example, if you pass in a string or array (by ref) and the C++ code
overruns the array. However, I am not sure if this is my problem.

I am passing in a number of "ref" params into the C++ function, these
are all arrays. I am passing in strings but these are "by value". I
have checked all the values going in and coming out and they all look
the exact same.

Any ideas on his would be greatly appreciated..

Thanks!
gwell

When you call unmanaged code, you have to pin the objects that you send
to it. The garbage collector can move managed object at any time, so you
have to tell it not to move the objects that the unmanaged code is using.

Use the fixed keyword to pin objects in memory.
 
M

Mattias Sjögren

Any ideas on his would be greatly appreciated..

Please post relevant parts of your code, it's hard to guess what's
wrong without it.

When you call unmanaged code, you have to pin the objects that you send
to it.

Sometimes you do, but usually you don't have to. The CLR takes care of
pinning arguments for the duration of the call if needed.


Mattias
 
G

gwell

Please post relevant parts of your code, it's hard to guess what's
wrong without it.


Sometimes you do, but usually you don't have to. The CLR takes care of
pinning arguments for the duration of the call if needed.

Mattias

Hi,

Here is my code.. I would be grateful if you could spot anything...
thanks

Note, some of these values (e.g. billRates is actually an array of
Double values). In my code I pass in the first element of the array
and I believe the C++ code can then use the pointer to get the rest of
the array. Is this OK?

Also, if I add a "ref" keyword to the two StringBuilder parameters the
DLL throws an exception. This seems strange seeing that the parameter
is declared as a pointer....

// C++ DLL Function
int WINAPI constructYC(long referenceDate,
char * currency,
double * billRates,
long * billEndDates,
bool * useBills,
double * billBumpAmounts,
long billSpotLag,
long billMaturityDatesLength,
long billsConvention,
double * billFuturesRates,
long * billFuturesStartDates,
long * billFuturesEndDates,
bool * useBillFutures,
double * billFuturesBumpAmounts,
long billFuturesStartDatesLength,
long billFuturesConvention,
double * specialDatesRates,
long * specialDatesStartDates,
long * specialDatesEndDates,
bool * useSpecialDates,
double * specialDatesBumpAmounts,
long specialStartDatesLength,
long specialDatesConvention,
double * bondCoupons,
double * swapRatesOrBondYields,
double * swapTenorsOrMaturities,
long * bondMaturityDates,
long * swapOrBondFrequencies,
bool * useSwapsBonds,
double * swapBondBumpAmounts,
long swapBondSpotLag,
long swapTenorsOrBondMaturityDatesLength,
long swapsOrBondsConvention,
bool enforceLinInterp,
long buildMethod,
bool billsOverrideFRAsAtStart,
bool billsOverrideFRAsAfterStart,
char * ycName,
long *holidayDates)


// C# P/Invoke method
[System.Runtime.InteropServices.DllImport(@"TheDLL.dll", EntryPoint =
"constructYCDll", CharSet = CharSet.Ansi)]
private static extern Int32 constructYCDll(
Int32 referenceDate,
StringBuilder currency,
ref Double billRates,
ref Int32 billEndDates,
ref Boolean useBills,
ref Double BillBumps,
Int32 billSpotLag,
Int32 billMaturityDatesLength,
Int32 billsConvention,
ref Double billFuturesRates,
ref Int32 billFuturesStartDates,
ref Int32 billFuturesEndDates,
ref Boolean useBillFutures,
ref Double BillFuturesBumps,
Int32 billFuturesStartDatesLength,
Int32 billFuturesConvention,
ref Double specialDatesRates,
ref Int32 specialDatesStartDates,
ref Int32 specialDatesEndDates,
ref Boolean useSpecialDates,
ref Double SpecialDatesBumps,
Int32 specialStartDatesLength,
Int32 specialDatesConvention,
ref Double bondCoupons,
ref Double swapRates,
ref Double swapTenors,
ref Int32 bondMaturityDates,
ref Int32 swapFrequencies,
ref Boolean useSwaps,
ref Double SwapBumps,
Int32 swapSpotLag,
Int32 swapTenorsLength,
Int32 swapsOrBondsConvention,
Boolean enforceLinInterp,
Int32 buildMethod,
Boolean billsOverrideFRAsAtStart,
Boolean billsOverrideFRAsAfterStart,
StringBuilder ycName,
ref Int32 holidayDates
);


// C# code to call the array
i = constructYCDll(refdate,
ccyCstring,
ref billRates[0],
ref billEndDates[0],
ref useBills[0],
ref billBumps[0],
billSpotLag,

billMaturityDatesLength,
shortConvention,
ref
billFuturesRates[0],
ref
billFuturesStartDates[0],
ref
billFuturesEndDates[0],
ref
useBillFutures[0],
ref
billFuturesBumps[0],

billFuturesStartDatesLength,
shortSpotLag,
ref
specialDatesRates[0],
ref
specialDatesStartDates[0],
ref
specialDatesEndDates[0],
ref
useSpecialDates[0],
ref
specialDatesBumps[0],

specialStartDatesLength,
shortSpotLag,
ref bondCoupons[0],
ref swapRates[0],
ref swapTenors[0],
ref
bondMaturityDates[0],
ref
swapFrequencies[0],
ref useSwaps[0],
ref swapBumps[0],
swapSpotLag,
swapTenorsLength,
longConvention,
enforceLinInterp,
buildMethod,

billsOverrideFRAsAtStart,

billsOverrideFRAsAfterStart,
ycName,
ref holidays[0]);
 
M

Mattias Sjögren

Note, some of these values (e.g. billRates is actually an array of
Double values). In my code I pass in the first element of the array
and I believe the C++ code can then use the pointer to get the rest of
the array. Is this OK?

Nope, you should pass the entire array. Change the parameter type to
double[].


Mattias
 
G

gwell

Note, some of these values (e.g. billRates is actually an array of
Double values). In my code I pass in the first element of the array
and I believe the C++ code can then use the pointer to get the rest of
the array. Is this OK?

Nope, you should pass the entire array. Change the parameter type to
double[].

Mattias

Hi I tried your suggestion and things work but I still get the
error... here is my code now if you can spot anything else? I am
going to create stubs this morning in C++ and try to narrow down
things... i think its going to be a slow process... thanks for your
help!

// C# P/Invoke method
[System.Runtime.InteropServices.DllImport(@"TheDLL.dll", EntryPoint =
"constructYCDll", CharSet = CharSet.Ansi)]
private static extern Int32 constructYC(
Int32 referenceDate,
StringBuilder currency, // This needs ref keyword
[In, Out] Double[] billRates,
[In, Out] Int32[] billEndDates,
[In, Out] Boolean[] useBills,
[In, Out] Double[] BillBumps,
Int32 billSpotLag,
Int32 billMaturityDatesLength,
Int32 billsConvention,
[In, Out] Double[] billFuturesRates,
[In, Out] Int32[] billFuturesStartDates,
[In, Out] Int32[] billFuturesEndDates,
[In, Out] Boolean[] useBillFutures,
[In, Out] Double[] BillFuturesBumps,
Int32 billFuturesStartDatesLength,
Int32 billFuturesConvention,
[In, Out] Double[] specialDatesRates,
[In, Out] Int32[] specialDatesStartDates,
[In, Out] Int32[] specialDatesEndDates,
[In, Out] Boolean[] useSpecialDates,
[In, Out] Double[] SpecialDatesBumps,
Int32 specialStartDatesLength,
Int32 specialDatesConvention,
[In, Out] Double[] bondCoupons,
[In, Out] Double[] swapRates,
[In, Out] Double[] swapTenors,
[In, Out] Int32[] bondMaturityDates,
[In, Out] Int32[] swapFrequencies,
[In, Out] Boolean[] useSwaps,
[In, Out] Double[] SwapBumps,
Int32 swapSpotLag,
Int32 swapTenorsLength,
Int32 swapsOrBondsConvention,
Boolean enforceLinInterp,
Int32 buildMethod,
Boolean billsOverrideFRAsAtStart,
Boolean billsOverrideFRAsAfterStart,
StringBuilder ycName, // This needs ref keyword
[In, Out] Int32[] holidayDates
);

// Call to method
i = constructYC(refdate,
ccyCstring,
billRates,
billEndDates,
useBills,
billBumps,
billSpotLag,

billMaturityDatesLength,
shortConvention,
billFuturesRates,

billFuturesStartDates,
billFuturesEndDates,
useBillFutures,
billFuturesBumps,

billFuturesStartDatesLength,
shortSpotLag,
specialDatesRates,

specialDatesStartDates,
specialDatesEndDates,
useSpecialDates,
specialDatesBumps,

specialStartDatesLength,
shortSpotLag,
bondCoupons,
swapRates,
swapTenors,
bondMaturityDates,
swapFrequencies,
useSwaps,
swapBumps,
swapSpotLag,
swapTenorsLength,
longConvention,
enforceLinInterp,
buildMethod,

billsOverrideFRAsAtStart,

billsOverrideFRAsAfterStart,
ycName,
holidays);
 
G

gwell

Nope, you should pass the entire array. Change the parameter type to
double[].

Hi I tried your suggestion and things work but I still get the
error... here is my code now if you can spot anything else? I am
going to create stubs this morning in C++ and try to narrow down
things... i think its going to be a slow process... thanks for your
help!

// C# P/Invoke method
[System.Runtime.InteropServices.DllImport(@"TheDLL.dll", EntryPoint =
"constructYCDll", CharSet = CharSet.Ansi)]
private static extern Int32 constructYC(
Int32 referenceDate,
StringBuilder currency, // This needs ref keyword
[In, Out] Double[] billRates,
[In, Out] Int32[] billEndDates,
[In, Out] Boolean[] useBills,
[In, Out] Double[] BillBumps,
Int32 billSpotLag,
Int32 billMaturityDatesLength,
Int32 billsConvention,
[In, Out] Double[] billFuturesRates,
[In, Out] Int32[] billFuturesStartDates,
[In, Out] Int32[] billFuturesEndDates,
[In, Out] Boolean[] useBillFutures,
[In, Out] Double[] BillFuturesBumps,
Int32 billFuturesStartDatesLength,
Int32 billFuturesConvention,
[In, Out] Double[] specialDatesRates,
[In, Out] Int32[] specialDatesStartDates,
[In, Out] Int32[] specialDatesEndDates,
[In, Out] Boolean[] useSpecialDates,
[In, Out] Double[] SpecialDatesBumps,
Int32 specialStartDatesLength,
Int32 specialDatesConvention,
[In, Out] Double[] bondCoupons,
[In, Out] Double[] swapRates,
[In, Out] Double[] swapTenors,
[In, Out] Int32[] bondMaturityDates,
[In, Out] Int32[] swapFrequencies,
[In, Out] Boolean[] useSwaps,
[In, Out] Double[] SwapBumps,
Int32 swapSpotLag,
Int32 swapTenorsLength,
Int32 swapsOrBondsConvention,
Boolean enforceLinInterp,
Int32 buildMethod,
Boolean billsOverrideFRAsAtStart,
Boolean billsOverrideFRAsAfterStart,
StringBuilder ycName, // This needs ref keyword
[In, Out] Int32[] holidayDates
);

// Call to method
i = constructYC(refdate,
ccyCstring,
billRates,
billEndDates,
useBills,
billBumps,
billSpotLag,

billMaturityDatesLength,
shortConvention,
billFuturesRates,

billFuturesStartDates,
billFuturesEndDates,
useBillFutures,
billFuturesBumps,

billFuturesStartDatesLength,
shortSpotLag,
specialDatesRates,

specialDatesStartDates,
specialDatesEndDates,
useSpecialDates,
specialDatesBumps,

specialStartDatesLength,
shortSpotLag,
bondCoupons,
swapRates,
swapTenors,
bondMaturityDates,
swapFrequencies,
useSwaps,
swapBumps,
swapSpotLag,
swapTenorsLength,
longConvention,
enforceLinInterp,
buildMethod,

billsOverrideFRAsAtStart,

billsOverrideFRAsAfterStart,
ycName,
holidays);


Hi,

So I tred to create some empty stubs and everything worked fine. After
that I worked through the C++ code and found the issue. There was a
function called "DllMain" (called when unloading the DLL I believe)
that was not freeing up some global variables. Some nice sloppy code
that just needed to be cleaned up.... once this was done no more
errors were raised.... phew.... took a lot of time to narrow down the
issue but the fix was quite simple....

Thanks for all your help.... there were some very valuable lessons
learnt there... Cheers! Gavin
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top