By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
449,143 Members | 1,267 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 449,143 IT Pros & Developers. It's quick & easy.

C# Unamanged Code Causing Access Violations

P: 6
Hey all -

I have some unmanaged code that I'm calling into with C# .NET 2.0, and everything works flawlessly in the debugger, but as soon as I run the application as a standalone executable it unexpectedly quits without throwing any exceptions. Even if I start the executable in the debugger it works okay. To see the failure, I need to start the application and then attach the debugger to the process. The function call will work okay twice and the data comes out okay, but on the third call it shuts down without any notice.

When running with Windows Debugging Tools I can see the access violation ("Access violation - code c0000005") and I'm pretty sure it's a NULL pointer exception, but can't figure out why or what to do about it.

I suspect it's because of the garbage collector moving data around, but I thought that the way I had created and passed the pointers in that they would be pinned.

The unmanaged function takes an input of int*, and double*, which it modifies during it's execution.

Here's a short code sample of the calling convention:

Expand|Select|Wrap|Line Numbers
  1. [DllImport("MyDll.dll", EntryPoint = "MyFunction", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
  2. private unsafe static extern int MyFunction(void* results, void* values);
  3.  
  4. private void CallFunction()
  5. {
  6.     int returnStatus = 0;
  7.     IntPtr resultPtr = IntPtr.Zero;
  8.     IntPtr valPtr = IntPtr.Zero;
  9.     int[] rawResults = new int[RESULT_SIZE];
  10.     double[] rawValues = new double[RESULT_SIZE];
  11.  
  12.     try
  13.     {
  14.         // Allocate memory
  15.         resultPtr = Marshal.AllocHGlobal(RESULT_SIZE * sizeof(int));
  16.         valPtr = Marshal.AllocHGlobal(RESULT_SIZE * sizeof(double));
  17.  
  18.         // Call external function
  19.         unsafe
  20.         {
  21.             returnStatus = MyFunction(resultPtr.ToPointer(), valPtr.ToPointer());
  22.         }
  23.  
  24.         Marshal.Copy((IntPtr)resultPtr, rawResults, 0, RESULT_SIZE);
  25.         Marshal.Copy((IntPtr)valPtr, rawValues, 0, RESULT_SIZE);
  26.     }
  27.     catch (Exception e)
  28.     {
  29.         string errMsg = String.Format("An exception has been caught attempting to call the external function. The following exception was trapped:\n\n{0}", e.Message);
  30.         MessageBox.Show(errMsg, "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
  31.     }
  32.     finally
  33.     {
  34.         if (resultPtr != IntPtr.Zero)
  35.             Marshal.FreeHGlobal(resultPtr);
  36.         if (valPtr != IntPtr.Zero)
  37.             Marshal.FreeHGlobal(valPtr);
  38.     }
  39. }
  40.  
I've been trying to figure out the best way to go about doing this, and at one time had tried using a structure with fixed variables, but that was also victim to the same problems. I like this approach better and seems more reliable but it's still crashing.

Any help is much appreciated!

Thanks
Sep 19 '08 #1
Share this Question
Share on Google+
1 Reply


P: 6
Well, in case someone stumbles upon something similar in the future, I thought I would post that I found the solution to this problem.

I did some more digging and realized that with data types int, and double supported natively by .NET, there is no need to manually create memory space and marshal the datatypes. Managed arrays passed into the function work just as well. The memory allocation was way overkill.

It doesn't seem as though this is affected by the garbage collector either.

Once I realized that the issue was not related to the .NET code, I began digging for issues with the DLL and the unmanaged code.

Apparently the function in the unmanaged code had too many static initializers that were eating up all the stack space. It would run fine once until the stack space was depleted and after that would throw null pointer references.

So I'm guessing the reason the code worked in the .NET debugger all the time was that the stack space for the DLL was pulled from the heap as opposed to the default for the compiled DLL. As soon as the executable ran on it's own it used the default stack space which was much lower causing the application to crash after a couple runs without throwing an exception. Just a guess, but I'm glad I finally found a solution to this.

If anyone can confirm or deny my suspicions (or provide an explanation), I would like to hear to any other ideas.

Here's a sample of what the new C# source looks like after cleaning it up:

Expand|Select|Wrap|Line Numbers
  1. {
  2.     public const int RESULT_SIZE = 10;
  3.  
  4.     [DllImport("MyDll.dll", EntryPoint = "MyFunction", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
  5.     private static extern int MyFunction(int[] results, double[] values);
  6.  
  7.     public int MyFunctionWrapper
  8.     {
  9.         int returnStatus = 0;
  10.         int[] rawResults = new int[RESULT_SIZE];
  11.         double[] rawValues = new double[RESULT_SIZE];
  12.  
  13.         returnStatus = MyFunction(rawResults, rawValues);
  14.  
  15.         if (returnStatus == 0)
  16.         {
  17.             // Do something with data
  18.             return returnStatus;
  19.         }
  20.         else
  21.         {
  22.             // Throw new exception
  23.             return returnStatus;
  24.         }
  25.     }
  26. }
  27.  
  28.  
Sep 20 '08 #2

Post your reply

Sign in to post your reply or Sign up for a free account.