Get the memory address of a .NET object (C #)

I am trying to track a bug in a mono executable environment where a variable is apparently assigned to a single valid object and then reassigned later to a dummy object, in particular

//early in code I allocate, fine var o = new object(); // valid allocation // later in code this is called, not fine lock(o) // <- is triggering bug due to "o" now referencing a nonsense memory location. 

I would like to know when the reference to "o" becomes nonsense, and for this I am looking for a way to determine the address "o" at different points in time in C # code. I know it looks like other questions with the answers β€œdon't do what the GC is,” but the GC is not working, so I need a workaround.

Does anyone know how I can determine the address of a mono object in C #? Perfectly communicates in unmanaged code or something else. (Any other tips on how to diagnose the underlying problem that was rated).

+6
garbage-collection c # mono
Aug 20 '14 at 16:43
source share
4 answers

It turns out that this is not possible in .NET directly, but can be achieved by changing the code of the executable file. To create a C # method that can read a memory address, make the following changes to the mono source code:

Modify gc-internal.h to add

 gpointer ves_icall_System_GCHandle_GetAddrOfObject (MonoObject *obj) MONO_INTERNAL; 

Modify gc.c to add:

 gpointer ves_icall_System_GCHandle_GetAddrOfObject (MonoObject *obj) { return (char*)obj; } 

Modify GCHandle.cs to add:

 MethodImplAttribute(MethodImplOptions.InternalCall)] private extern static IntPtr GetAddrOfObject(object obj); public static IntPtr AddrOfObject(object o) { IntPtr res = GetAddrOfObject(o); return res; } 

Edit icall-def.h to add

 ICALL(GCH_6, "GetAddrOfObject", ves_icall_System_GCHandle_GetAddrOfObject) 

Note that they must be in order, so add it above the GetAddrOfPinnedObject line Rebuild

Finally, call it with C #

 for (int i = 0; i < 100; i++) { object o = new object (); var ptr = GCHandle.AddrOfObject (o); Console.WriteLine ("Address: " + ptr.ToInt64().ToString ("x")); } 
+5
Aug 21 '14 at 17:57
source share

You can use the GCHandle construct to accomplish this.

 GCHandle objHandle = GCHandle.Alloc(obj,GCHandleType.WeakTrackResurrection); int address = GCHandle.ToIntPtr(objHandle).ToInt32(); 

Where 'obj' is the object whose address you are trying to get.

+11
Aug 20 '14 at 4:53
source share

You cannot get the address of a managed entity in managed code at all. If an object has a field of type int, you can accept it using a fixed C # operator, and then you will have a pointer inside the object. For debugging purposes, you can make some assumptions and get the offset of the base pointer of the object (on 32-bit platforms, the size of the object header on mono is 8 bytes, 16 bytes on 64-bit architectures).

Your error report claims that you are using a Boehm collector, and this collector does not move objects in memory, the error may be caused by incorrect memory corruption, if the object is incorrectly freed or some other logic error in the GC (I'm not sure if the zero the size you specify matters because the managed entity has at least an 8-16 byte header).

+1
Aug 21 '14 at 7:36 on
source share

My alternatives ... Also @ This similar question

 #region AddressOf /// <summary> /// Provides the current address of the given object. /// </summary> /// <param name="obj"></param> /// <returns></returns> [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public static System.IntPtr AddressOf(object obj) { if (obj == null) return System.IntPtr.Zero; System.TypedReference reference = __makeref(obj); System.TypedReference* pRef = &reference; return (System.IntPtr)pRef; //(&pRef) } /// <summary> /// Provides the current address of the given element /// </summary> /// <typeparam name="T"></typeparam> /// <param name="t"></param> /// <returns></returns> [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public static System.IntPtr AddressOf<T>(T t) //refember ReferenceTypes are references to the CLRHeader //where TOriginal : struct { System.TypedReference reference = __makeref(t); return *(System.IntPtr*)(&reference); } [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static System.IntPtr AddressOfRef<T>(ref T t) //refember ReferenceTypes are references to the CLRHeader //where TOriginal : struct { System.TypedReference reference = __makeref(t); System.TypedReference* pRef = &reference; return (System.IntPtr)pRef; //(&pRef) } /// <summary> /// Returns the unmanaged address of the given array. /// </summary> /// <param name="array"></param> /// <returns><see cref="IntPtr.Zero"/> if null, otherwise the address of the array</returns> [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public static System.IntPtr AddressOfByteArray(byte[] array) { if (array == null) return System.IntPtr.Zero; fixed (byte* ptr = array) return (System.IntPtr)(ptr - 2 * sizeof(void*)); //Todo staticaly determine size of void? } #endregion 
0
May 04 '16 at
source share



All Articles