As far as I can tell this all refers to objects on the GC Heap.
The point is I am referring to specifically STACK memory.
I have posted an example which seems to suggest that stack memory is being corrupted during an API call passing stack memory as a buffer:
http://social.msdn.microsoft.com/Forums/en-US/clr/thread/3779c1ee-90b8-4a6a-9b14-f48d709cb27c
If stack memory needs to be pinned, then this seems to break the idea of "It Just Works". In unmanaged C++ we can declare a stack buffer and then pass a pointer to it to an API function. However if moving to managed code requires that to be pinned, it would seem to fundamentally undermine "It Just Works".
It is confusing how the MSDN docs for pin_ptr seem to say it is only to prevent objects moving however it is also possible to Pin value types which would seem to be on the stack and should not move anyway.
I specifically raise the question of whether the stack memory is treated the same way in managed or unmanaged code. When MSIL debugging I have found it impossible to view the stack and there is no stack viewer tool for that. I have heard, but am not sure, that there is no "real" stack in MSIL and instead the virtual machine CLR is free to optimize, for example using free processor registers instead of actual memory. It is unclear whether this is true, and, whether it would apply to stack as in parameter passing, or stack as in local variable memory.
An odd effect in the above sample project is that pin_ptr on the corrupting object seems to cure the problem. however the object is on the STACK and should not need pinning. Could it be that the /CLR interprets pin_ptr as not only "do not move this object" but also "leave this area as true memory and do not attempt register optimizations upon it" which would cause it to remain pure for the duration of the pin?
I would specifically like to know if the /CLR is clever enough to say avoid optimizations of its in-method stack memory during a call to an API, but would possibly not give me the same grace in the above example due to the direct loading of NTDLL and the way the function is declared as a typedef.
I have considered adding Marshalling attributes to the function typedef but seem unable to do so. I note there are no MarshallAs attributes on WinAPI defs.
I have managed to break into the project above using __debugbreak() immediately before the NTDLL call however this only gives me a managed debug mode which seems unable to step into native code. I cannot write "asm int 3" because x64 does not support it. I can see, however, that the errant value NumberOfPairs is being passed at a memory location pointed to by a register, not as a register itself.