Ran into an interesting problem trying to create a C# pointer array to pass to a vendor DLL that Google did not immediately solve for me. Here’s a quick blog post to hopefully light the way for some other developer with a similar problem. I needed to call into the Atmel provided DLL for updating a flash memory chip connected to one of their AT91SAM9261 processors because version 2.12 finally supports 64-bit USB drivers on Windows (well at least Intel chipsets). The language in use for this software project is C#. Unfortunately, the vendor DLL does some shady things with memory access. Specifically their very first call necessary to acquire the device string used to open the device requests a pointer to a single buffer, but then assumes the next 9 memory addresses contain pointers to 9 more buffers. C# correctly objects to a function accessing memory it never asked permission to access. So how do you tell C# to let you do dumb things because a third party library won’t work unless you let it violate C#’s memory protection scheme? C#’s memory management is a great thing to simplify dynamic memory allocation. But in this case, the DLL was requiring me to not only bypass that memory protection but to allow it to access memory beyond its requested parameter signature.
We have a lot of experience over the years with this AT91SAM9261 processor. A current project uses TCL scripts to access the Atmel tools to program the flash this processor boots from. If we could access the Atmel provided DLL directly from C#, we could remove the TCL dependency, gain 64 bit drivers, and have cleaner, more easily testable code. But the very first function call in their example needed to use the DLL does some unsafe stuff with memory access. The function function “AT91Boot_Scan” requires a byte pointer as its sole argument BUT it expects that byte pointer to be the first element of an array of byte pointers, each pointing to a 100 byte buffer that the DLL could populate with detected device strings. Look at the snippet from their example visual C++ example project:
// MANDATORY: Allocate memory for each string in the table
for (UINT i=0; i<10; i++)
pTest[i] = (char *)malloc(100);
// Scan all devices connected
Note that their documentation for this function below contradicts their example code above (and their documentation snippet would crash because on my system it wrote to 7 buffers, not 5)
From their pdf documenting the API
Note: All table entries must have been allocated prior to using the AT91Boot_Scan function. Each string must be allocated from the application and must have a size superior to 80 bytes. That string is used to recover, USB or JTAG box device name which is then replaced by a reduced symbolic name.
for (UINT i=0; i<5; i++)
strConnectedDevices[i] = (CHAR *)malloc(100);
/* AT91Boot_Scan may return code similar to that below:
strConnectedDevices : \usb\ARM0
strConnectedDevices : \jlink\ARM0
strConnectedDevices : COM11 */
So how do you so something inherently memory unsafe like pass a pointer knowing the called function will assume there are 9 more pointers in memory immediately following that one?
I struggled with various combinations of the “unsafe” keyword and “fixed” to build an array of pointers. But the fundamental problem was I could easily get a pointer and pass that pointer, but the memory manager would immediately barf when I called into the DLL and it tried to walk the next 9 addresses.
It stumped me for about half a day and I called in my coworkers for help and they couldn’t figure it out either. Eventually the light bulb went off: Forget building an array, that will never work because the function forces you to pass a single pointer and C# will always die when the Atmel DLL tries to access array elements for an array it was not passed and never asked for.
The solution: Do it by hand in one big block of memory. The code that worked turned out to be far more simple than expected:
[csharp]//allocate block of raw bytes big enough for ten 100 byte buffers
// and ten pointers. Since we are calling into a 32 bit dll, they
// use 4 byte pointers so we need 1040 bytes (10*100 + 10*4)
byte byteArray = new byte;
fixed (byte * pByteArray = byteArray)
for (var i = 0; i < 10; i++ )
var memoryLocation = pByteArray + 40 + i*100;
var asInt = new IntPtr(memoryLocation).ToInt32();
var asBytes = BitConverter.GetBytes(asInt);
Buffer.BlockCopy(asBytes, 0, byteArray, i*4,4);
Simply declare a block of raw bytes big enough for the pointer table and the ten buffers. Then populate the first 40 bytes of that memory space with ten pointers to ten 100 byte buffers. The C# memory management is happy now because it sees those 1040 bytes as one big sandbox that the DLL can do whatever it wants in.
Hope this helps somebody trying to make the Atmel DLLs work with the C# memory protection.