469,578 Members | 1,245 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,578 developers. It's quick & easy.

GC still seemingly moving pinned pointers

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();

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);

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++.


The UnmanagedFunction is legacy code that does it's own strncpy into a
member structure, and does not store the pointer. It assumes the
pointer is only valid durring the call.

Lance Orner
Nov 17 '05 #1
1 1136
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 Sjögren [MVP] mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Please reply only to the newsgroup.
Nov 17 '05 #2

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

reply views Thread by HeroOfSpielburg | last post: by
7 posts views Thread by _BNC | last post: by
1 post views Thread by Pierre | last post: by
16 posts views Thread by Atmapuri | last post: by
4 posts views Thread by guiromero | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.