GCHandle.FromIntPointer does not work as expected - c#

Here's a very simple (complete) program for exercising the use of GCHandle.FromIntPointer:
using System;
using System.Runtime.InteropServices;
namespace GCHandleBugTest
{
class Program
{
static void Main(string[] args)
{
int[] arr = new int[10];
GCHandle handle = GCHandle.Alloc(arr, GCHandleType.Pinned);
IntPtr pointer = handle.AddrOfPinnedObject();
GCHandle handle2 = GCHandle.FromIntPtr(pointer);
}
}
}
Note that this program is essentially a transliteration of the procedure described in English on CLR via C# (4e) on page 547. Running it, however, results in an unmanaged exception like:
Additional Information: The runtime has encountered a fatal error. The address of the error was at 0x210bc39b, on thread 0x21bc. The error code is 0xc0000005. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack.
Thinking that this might be a bug in .NET 4.5, and since I don't see anything obviously wrong, I tried exactly the same program in Mono on Linux (v2.10.8.1). I got the slightly more informative but still puzzling exception GCHandle value belongs to a different domain.
As far as I am aware, the handle really does belong to the same AppDomain as the code where I call GCHandle.FromIntPtr. But the fact that I see an exception in both implementations makes me suspect that I am missing some important detail. What's going on here?

You've got the wrong mental model. FromIntPtr() can only convert back the value you got from ToIntPtr(). They are convenience methods, handy in particular to store a reference to a managed object (and keep it alive) in unmanaged code. The gcroot<> template class relies on it, used in C++ projects. It is convenient because the unmanaged code only has to store the pointer.
The underlying value, the actual pointer, is called a "handle" but it is really a pointer into a table that the garbage collector maintains. The table create extra references to objects, in addition to the ones that the garbage collector finds. In essence allowing a managed object to survive even though the program no longer has a valid reference to the object.
GCHandle.AddrOfPinnedObject() returns a completely different pointer, it points to the actual managed object, not the "handle". The "belongs to a different domain" exception message is understandable since the table I mentioned is associated with an AppDomain.
The crash in .NET 4.5 strongly looks like a bug. It does perform a test with an internal CLR function called MarshalNative::GCHandleInternalCheckDomain(). The v2 version of the CLR raises an ArgumentException with the message text "Cannot pass a GCHandle across AppDomains.". But the v4 version crashes inside this method which in turn generates the ExecutionEngineException. This does not look intentional.
Feedback report filed at connect.microsoft.com

AddrOfPinnedObject is not the opposite of FromIntPtr. You want ToIntPtr instead:
IntPtr pointer = handle.ToIntPtr ();
GCHandle handle2 = GCHandle.FromIntPtr (pointer);
FromIntPtr does not take the address of the object, it takes an opaque value (which happens to be defined as IntPtr), which is used to retrieve the object with ToIntPtr.

Related

pin_ptr cannot declare a managed object in an unmanaged class

I have unmanaged class. In that class I have a managed object. Now I want a pin_ptr for the managed object in my unmanged class. And when I try to do this I get this error "error C3265: cannot declare a managed _pinnedProject in an unmanaged ProjectWrapper How can I achieve this?
Here is the code.
class ProjectWrapper
{
private:
msclr::auto_gcroot<Project^> _project; // --> This works fine,
pin_ptr<msclr::auto_gcroot<Project^>> _pinnedProject; // ---> This gives error
public:
ProjectWrapper()
{
_project = gcnew Project();
pin_ptr<msclr::auto_gcroot<Project^>> anotherPinnedProject = &_project; // --> This one works,
//_pinnedProject = _project; // --> I want to use this instead of above live,
}
}
The MSDN article about pin_ptr<> is not shy about telling you why this cannot work:
Pinning pointers can only be declared as non-static local variables on the stack.
Pinning pointers cannot be used as:
function parameters
the return type of a function
a member of a class
the target type of a cast.
Which is all for a rather good reason, this kind of object pinning is very efficient. It doesn't require an explicit call into the CLR at all, the pin is discovered when the garbage collector walks the stack looking for roots. That requires the object reference to be a local variable, the compiler emits it in the MSIL with the [pinned] attribute. Also exposed in the C# language with the fixed keyword.
So, no can do, nor should you pursue this. Pinning an object for a long time is very detrimental to GC, it is a rock in the road and prevents heap segments from getting recycled. You should only pin at the exact moment in time that you need the pointer to be stable, that moment only occurs inside of the code of the function that uses the pointer.
If you want to wish this problem away then you need to fall back to the heavy pin. That requires GCHandle::Alloc(), passing GCHandleType::Pinned. You get the pointer you need from AddrOfPinnedObject(), release with the Free() method.

Are there memory security levels in .NET interop?

I have a quite strange problem:
I am testing several function calls to a unmanaged C dll with NUnit. The odd thing is, the test fails when it runs normally, but when i run it with the debugger (even with no break point) it passes fine.
So, has the debugger a wider memory access as the plain NUnit application?
i have isolated the call which fails. its passing back a char pointer to a string, which the marshaller should convert to a C# string. the C side looks like this:
#define get_symbol(a) ((a).a_w.w_symbol->s_name)
EXTERN char *atom_get_symbol(t_atom *a);
...
char *atom_get_symbol(t_atom *a) {
return get_symbol(*a);
}
and the C# code:
[DllImport("csharp.dll", EntryPoint="atom_get_symbol")]
[return:MarshalAs(UnmanagedType.LPStr)]
private static extern string atom_get_symbol(IntPtr a);
the pointer which is returned from c is quite deep inside the code and part of a list. so do i just miss some security setting?
EDIT: here is the exception i get:
System.AccessViolationException : (translated to english:) there was an attempt to read or write protected memory. this might be an indication that other memory is corrupt.
at Microsoft.Win32.Win32Native.CoTaskMemFree(IntPtr ptr)
at ....atom_get_symbol(IntPtr a)
SOLUTION:
the problem was, that the marshaller wanted to free the memory which was part of a C struct. but it sould just make a copy of the string and leave the memory as is:
[DllImport("csharp.dll", EntryPoint="atom_get_symbol")]
private static extern IntPtr atom_get_symbol(IntPtr a);
and then in the code get a copy of the string with:
var string = Marshal.PtrToStringAnsi(atom_get_symbol(ptrToStruct));
great!
This will always cause a crash on Vista and up, how you avoided it at all isn't very clear. The stack trace tells the tale, the pinvoke marshaller is trying to release the string buffer that was allocated for the string. It always uses CoTaskMemFree() to do so, the only reasonable guess at an allocator that might have been used to allocate the memory for the string. But that rarely works out well, C or C++ code almost always uses the CRT's private heap. This doesn't crash on XP, it has a much more forgiving memory manager. Which produces undiagnosable memory leaks.
Notable is that the C declaration doesn't give much promise that you can pinvoke the function, it doesn't return a const char*. The only hope you have is to declare the return type as IntPtr instead of string so the pinvoke marshaller doesn't try to release the pointed-to memory. You'll need to use Marshal.PtrToStringAnsi() to convert the returned IntPtr to a string.
You'll need to test the heck out of it, call the function a billion times to ensure that you don't leak memory. If that test crashes with an OutOfMemoryException then you have a big problem. The only alternative then is to write a wrapper in the C++/CLI language and make sure that it uses the exact same version of the CRT as the native code so that they both use the same heap. Which is tricky and impossible if you don't have the source code. This function is just plain difficult to call from any language, including C. It should have been declared as int atom_get_symbol(t_atom* a, char* buf, size_t buflen) so it can be called with a buffer that's allocated by the client code.

.NET Unsafe string manipulation

I use next unsafe code for string modifying:
public static unsafe void RemoveLastOne(ref string Str1)
{
if (Str1.Length < 1)
return;
int len = Str1.Length - 1;
fixed (char* pCh1 = Str1)
{
int* pChi1 = (int*)pCh1;
pCh1[len] = '\0';
pChi1[-1] = len;
}
}
But some time later my C# programm crash with exception:
FatalExecutionEngineError:
"The runtime has encountered a fatal error.
The address of the error was at 0x6e9a80d9, on thread 0xcfc. The error
code is 0xc0000005. This error may be a bug in the CLR or in the
unsafe or non-verifiable portions of user code. Common sources of this
bug include user marshaling errors for COM-interop or PInvoke, which
may corrupt the stack."
If I change function "RemoveLastOne" to "Str1 = Str1.Remove(Str1.Length - 1);" program works fine.
Why exception happens? And how I can implement unsafe change string in C# correctly?
String values in .Net are intended to be immutable. In this function you are taking an immutable value, mutating it in several visible ways (content and length) not to mention writing data before the original. I'm not surprised at all that this would result in a later CLR crash as it special cases String values in several places and writing before the pointer is simply dangerous.
I can't really see a reason why you'd want to do the unsafe manipulation here. The safe code is straight forward and won't cause these types of hard to track down bugs.
Unsafe string manipulation is inherently incorrect. .NET strings aren't supposed to be edited, and it's most likely that there is code in the framework that is built around the assumption that a string will never change. Anything that relies on String.GetHashCode() comes immediately to mind, but there might be behind-the-scenes optimizations or sanity checks. Presumably it's something like that which is causing the CLR error.
If you're finding, after profiling, that .NET's immutable string implementation does not fit your needs, the easiest mutable alternative that would let you modify its length is a List<char>.

Why is memory access in the lowest address space (non-null though) reported as NullReferenceException by .NET?

This causes an AccessViolationException to be thrown:
using System;
namespace TestApplication
{
internal static class Program
{
private static unsafe void Main()
{
ulong* addr = (ulong*)Int64.MaxValue;
ulong val = *addr;
}
}
}
This causes a NullReferenceException to be thrown:
using System;
namespace TestApplication
{
internal static class Program
{
private static unsafe void Main()
{
ulong* addr = (ulong*)0x000000000000FF;
ulong val = *addr;
}
}
}
They're both invalid pointers and both violate memory access rules.
Why the NullReferenceException?
This is caused by a Windows design decision made many years ago. The bottom 64 kilobytes of the address space is reserved. An access to any address in that range is reported with a null reference exception instead of the underlying access violation. This was a wise choice, a null pointer can produce reads or writes at addresses that are not actually zero. Reading a field of a C++ class object for example, it has an offset from the start of the object. If the object pointer is null then the code will bomb from reading at an address that's larger than 0.
C# doesn't have quite the same problem, the language guarantees that a null reference is caught before you can call an instance method of a class. This is however language specific, it is not a CLR feature. You can write managed code in C++/CLI and generate non-zero null pointer dereferences. Calling a method on a nullptr object works. That method will merrily execute. And call other instance methods. Until it tries to access an instance variable or call a virtual method, which requires dereferencing this, kaboom then.
The C# guarantee is very nice, it makes diagnosing null reference problems much easier since they are generated at the call site and don't bomb somewhere inside a nested method. And it is fundamentally safer, the instance variable might not trigger an exception on extremely large objects when its offset is larger than 64K. Pretty hard to do in managed code btw, unlike C++. But doesn't come for free, explained in this blog post.
A null reference exception and an access violation exception are both raised by the CPU as an access violation. The CLR then has to guess whether the access violation should be specialized to a null reference exception or left as the more general access violation.
It is evident from your results that the CLR infers that access violations at addresses very close to 0 are caused by a null reference. Because they were almost certainly generated by a null reference plus field offset. Your use of unsafe code fools this heuristic.
This may be a semantics issue.
Your first example is trying to dereference a pointer whose content is the address Int64.MaxValue, not a pointer to a variable that has a value of Int64.MaxValue.
Looks like you're trying to read the value stored at the address Int64.MaxValue, which is, apparently not in the range that's owned by your process.
Do you mean something like this?
static unsafe void Main(string[] args)
{
ulong val = 1;// some variable space to store an integer
ulong* addr = &val;
ulong read = *addr;
Console.WriteLine("Val at {0} = {1}", (ulong)addr, read);
#if DEBUG
Console.WriteLine("Press enter to continue");
Console.ReadLine();
#endif
}
from http://msdn.microsoft.com/en-us/library/system.accessviolationexception.aspx
Version Information
This exception is new in the .NET Framework version 2.0. In earlier
versions of the .NET Framework, an access violation in unmanaged code
or unsafe managed code is represented by a NullReferenceException in
managed code. A NullReferenceException is also thrown when a null
reference is dereferenced in verifiable managed code, an occurrence
that does not involve data corruption, and there is no way to
distinguish between the two situations in versions 1.0 or 1.1.
Administrators can allow selected applications to revert to the
behavior of the .NET Framework version 1.1. Place the following line
in the Element section of the configuration file for the
application:
other <legacyNullReferenceExceptionPolicy enabled = "1"/>

Displaying the value of a reference to an object

In C++ it is fairly simple to display the actual value of a pointer to an object. For example:
void* p = new CSomething();
cout << p;
Is there a way to do something like this in .NET?
The value of doing this would/could only be educational, e.g. for purposes of demonstration as in displaying a value for students to see rather than just comparing for reference equality or null (nothing) to prove shallow copies, immutability etc.
You can use GCHandle to get the address of a pinned object. The GC can move objects around so the only sensible address to get is one of a pinned object.
GCHandle handle = GCHandle.Alloc(obj, GCHandleType.Pinned);
Console.WriteLine(handle.AddrOfPinnedObject().ToInt32());
handle.Free();
Remember though that GCHandle will only pin objects that are primitive or blittable types. Some objects are blittable (and you can set it up for demo purposes so it works) but any reference type will not be blittable.
You'll need to add an explicit blittable description using [StructLayout(LayoutKind.Sequential)] or use the debugger to directly inspect addresses of object that do not meet these criteria.
If this is for education purposes, I suggest you use a debugger instead. If you load SOS.dll (which is part of the .NET framework) into WinDbg or even Visual Studio, you can examine the actual objects in memory.
E.g. to list the heap use the !dumpheap -stat command. The !do command dumps a mananaged object on the specified memory address and so forth. SOS has numerous commands that will let you examine internal .NET structures, so it is a really useful tool for learning more about the runtime.
By using the debugger for this, you're not restricted to looking at demo applications. You can peek into the details of real applications. Also, you'll pick up some really useful debugging skills.
There are several excellent introductions to debugging using WinDbg + SOS. Check Tess' blog for lots of tutorials.
RuntimeHelpers.GetHashCode will give you an identity-based hash code. In practice, this is probably based on address. As explained:
"RuntimeHelpers.GetHashCode is useful
in scenarios where you care about
object identity. Two strings with
identical contents will return
different values for
RuntimeHelpers.GetHashCode, because
they are different string objects,
although their contents are the same."
Interning of string literals is the main possible exception. This is actually the same in C++.
I understand that if you provide the compiler the /unsafe option, you will be allowed to write 'unsafe' code, and with it have access to pointers.
I haven't tested this but found it in this artice
Edit:
Seems the main thing to remember is that you would have to mark any code using unsafe code with the unsafe keyword:
unsafe public static void Main()
In .Net you don't work with pointers at all. So you would create reference objects, of which you can always see the value.
When comparing reference objects, the references are compared, not the actual values! (Except for comparing strings, where the '==' is overloaded).
Maybe an .Net example of what you want to demonstrate would elaborate things...
You can retrieve the address of an object in .NET, such as with unsafe code, but the address you get back will only be temporary -- it'll be a snapshot as of the point where you take the address.
The next time a garbage collection happens, the address of your object is likely to change:
If the object is no longer referenced from anywhere, it will be collected, and some other object will occupy that address
If the object is still being referenced, it will probably be promoted to a higher generation (and therefore moved to a different GC heap). Alternatively, if it's already in generation 2, it will probably be moved in memory as the heap is compacted.
The existence of the garbage collector is the reason why the int* pointer in #Jesper's exists in the scope of a { } block. The pointer is fixed only within that block; once execution leaves the block, the object is entitled to be collected and/or moved.
unsafe
{
object o = new Object();
int *ptr = &o; //Get address
Console.WriteLine((int)ptr); //Write address
}
You need to compile this with the /unsafe switch

Categories

Resources