GC still seemingly moving pinned pointers

L

Lance Orner

I wrote this letter to a colleague, and I thought I'd share it here:

---

We had a problem with pointers being passed between managed C++ and
unmanaged C++ code, but it only occurred once in every 2000-3000
calls. There were some String* objects in the managed code, which
were marshalled into IntPtr* objects. This was cast into a const char
__pin* and passed to some unmanaged C++ code. When the problem would
occur, the breakpoint would show that the char* was pointing to
invalid data, and viewing the call stack, the managed code is pointer
to valid data, but that pointer is different than what the unmanaged
code has. I can only suppose that GC moved the pointer, but the
unmanged code didn't track the moved data. This is exactly what
pinned pointers is supposed to prevent.

From memory, it looked something like:

IntPtr serial_p = Marshal::StringToHGlobalAnsi(serial);
const char __pin* serial_c = (const char*)serial_p.ToPointer();
UnmanagedFunction(serial_c);

The char* is pinned, but after thousands of calls, it would crash
once, and when I caught it, the pointers viewed in the managed and
unmanaged code were different.

Final solution: don't pass pointers from the heap which could be
GCed, but pointers from the stack, which I know won't move.

IntPtr serial_p = Marshal::StringToHGlobalAnsi(serial);
char serial_c[SERIAL_LENGTH];
strncpy(serial_c, (const char*)serial_p.ToPointer(), SERIAL_LENGTH);
UnmanagedFunction(serial_c);

This is now working perfectly.

There were three of us there when we saw the pointer irregularites,
and it looked really strange. Even if that was caused by some
artifact of the debugger, the final solution now works perfectly still
says that there is a problem passing heap pointers, even pinned ones.
This may be a problem only in managed/unmanaged C++.
 
M

Mattias Sjögren

Lance,
IntPtr serial_p = Marshal::StringToHGlobalAnsi(serial);
const char __pin* serial_c = (const char*)serial_p.ToPointer();

StringToHGlobalAnsi allocates memory from an unmanaged heap, so it's
not subject to GC. Hence there's no need to use a pinning pointer.

Do you remember to call FreeHGlobal?



Mattias
 

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