I am trying to track down a bug in the mono runtime where a variable appears to be allocated to one valid object, and then is reassigned later to a bogus object, specifically
//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 to do this am looking for a way to determine the address of "o" at various timepoints within the C# code. I know is similar to other questions with answers "don't do that there is a GC", but the GC doesn't work so I need a workaround.
Does anyone know how I can determine the address of a mono object in C#? Am fine to link in unmanaged code or whatever. (Any other clues to ways to diagnose the main issue appreciated to).
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
You should be able to 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're trying to get.
Turns out this is not possible in .NET directly, but can be accomplished by altering the mono runtime code. To create a C# method that can read the memory address, make the following changes to the mono source code:
Alter gc-internal.h to add
gpointer ves_icall_System_GCHandle_GetAddrOfObject (MonoObject *obj) MONO_INTERNAL;
Alter gc.c to add:
gpointer ves_icall_System_GCHandle_GetAddrOfObject (MonoObject *obj) {
return (char*)obj;
}
Alter 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;
}
Alter icall-def.h to add
ICALL(GCH_6, "GetAddrOfObject", ves_icall_System_GCHandle_GetAddrOfObject)
Note that these must be in order, so add it above the GetAddrOfPinnedObject line Rebuild
Finally, call it from C#
for (int i = 0; i < 100; i++) {
object o = new object ();
var ptr = GCHandle.AddrOfObject (o);
Console.WriteLine ("Address: " + ptr.ToInt64().ToString ("x"));
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With