A couple of weeks ago a reader of this blog approached me via Email (you can always Email me and I’ll do my best to help you if I have the time and if I can 😉 ) with a problem regarding the exception “Attempted to read or write protected memory. This is often an indication that other memory is corrupt” (which is of type System.AccessViolationException).
I immediately asked if there was some P/Invoke (Platform Invoke) code.
“Why?”, do you ask. Because in 90% of the cases, this exception occurs when a call to a P/Invoke function (either calling a Win32 API or some custom native code of your own) returns. It might even be that this piece of code you are calling is purely managed, but in its implementation it uses P/Invoke and you are not aware of it.
The main problem with P/Invoke is that .NET is very sensitive to memory corruption. If you step over some internal GC structure or some of the .NET meta data for a class things get really bad.
The causes for this error can stem from different reasons:
- You passed a wrongly referenced pointer.
- Inside the function there is a bug in the form of “Off-By-One” or some other memory smear or misuse.
There are two main scenarios in P/Invoke code. The first is when you correctly use the various marshaling and P/Invoke type matching simply pass a managed object (such as a string) to the function and the P/Invoke layer takes care of all the rest. In this case, you might get the exception mentioned above if:
The second is when you use IntPtr because you need to pass a pointer to a pointer or you need to receive some kind of a strange memory structure. In this case, make sure that if you pass an IntPtr buffer that you have allocated using something like Marshal.AllocHGlobal or Marshal.AllocCoTaskMem you allocated enough memory.
- You didn’t define the marshaling attributes correctly (i.e., you should have used native pointer – IntPtr – and you didn’t)
- You did define everything correctly, but inside the native function there is a memory related bug
If you do start to get this exception try to do the following things:
- If you are using Marshalling attributes (MarshalAs and friends) make sure they are correct. Make sure the markings for in, out and ref are correct as well. This is a very important step. Take the time to check each and every function argument. It can save you a lot of debugging time.
- Make sure that you are passing the right type of objects. This is specifically important if you are using IntPtrs. Make sure that you pass the right type of pointer to the function.
- If you are calling a Windows function, there is a chance (though its usually very slim) that they do have some kind of an allocation bug, but before running to Microsoft Support, make sure you are passing the right type of pointers. If you are still in doubt, write a native sample code that calls this function and run it lots of time with additional checks to see that the integrity of the memory passed is OK.
- If you are calling your own function, do the same as I have suggested in the point above, but in most cases, it usually a problem within the native function (if the passed pointer types are correct and the marshaling attributes are correct as well).
Remember, P/Invoke is one of .NET’s greatest features. It’s VERY fast (performance wise) and very easy to use, but its also very easy to make mistakes that can crash your whole .NET application. Use it wisely!