Ottieni l’indirizzo di memoria di .NET Object (C #)

Sto cercando di rintracciare un bug nel runtime mono in cui una variabile sembra essere allocata ad un object valido, e quindi viene riassegnata successivamente ad un object fasullo, in particolare

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

Vorrei sapere quando il riferimento a “o” diventa insensato, e per farlo sto cercando un modo per determinare l’indirizzo di “o” in vari punti del codice C #. So che è simile ad altre domande con le risposte “non fare che c’è un GC”, ma il GC non funziona quindi ho bisogno di una soluzione alternativa.

Qualcuno sa come posso determinare l’indirizzo di un object mono in C #? Sto bene per colbind in codice non gestito o qualsiasi altra cosa. (Qualsiasi altro indizio sui modi per diagnosticare il problema principale apprezzato).

Dovresti essere in grado di utilizzare il costrutto GCHandle per ottenere ciò.

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

Dove ‘obj’ è l’object di cui stai cercando di ottenere l’indirizzo.

Si scopre che questo non è ansible direttamente in .NET, ma può essere ottenuto modificando il codice runtime mono. Per creare un metodo C # in grado di leggere l’indirizzo di memoria, apportare le seguenti modifiche al codice sorgente mono:

Alterare gc-internal.h per aggiungerlo

 gpointer ves_icall_System_GCHandle_GetAddrOfObject (MonoObject *obj) MONO_INTERNAL; 

Alterare gc.c per aggiungere:

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

Modifica GCHandle.cs per aggiungere:

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

Alterare icall-def.h per aggiungerlo

 ICALL(GCH_6, "GetAddrOfObject", ves_icall_System_GCHandle_GetAddrOfObject) 

Nota che questi devono essere in ordine, quindi aggiungilo sopra la riga Ricostruisci GetAddrOfPinnedObject

Infine, chiamalo da C #

 for (int i = 0; i < 100; i++) { object o = new object (); var ptr = GCHandle.AddrOfObject (o); Console.WriteLine ("Address: " + ptr.ToInt64().ToString ("x")); } 

Non è ansible ottenere l’indirizzo di un object gestito in codice gestito, in generale. Se l’object ha un campo come un int, potresti prendere il suo indirizzo con l’istruzione C # fissa e quindi avresti un puntatore all’interno dell’object. A scopo di debug, è ansible formulare alcune ipotesi e ottenere l’offset dal puntatore di base dell’object (su piattaforms a 32 bit la dimensione dell’intestazione dell’object su mono è 8 byte, 16 byte su architetture a 64 bit, al momento).

La tua segnalazione di bug afferma che stai utilizzando il programma di raccolta Boehm, e che il collector non sposta gli oggetti in memoria, il bug potrebbe essere causato da qualche corruzione della memoria non correlata, dall’errato errore dell’object o da qualche altro bug di logica nel GC (Non sono sicuro che la dimensione zero che hai indicato sia rilevante, dal momento che un object gestito ha almeno l’intestazione 8-16 byte).

Le mie alternative … Anche @ Questa domanda simile

 #region AddressOf ///  /// Provides the current address of the given object. ///  ///  ///  [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) } ///  /// Provides the current address of the given element ///  ///  ///  ///  [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public static System.IntPtr AddressOf(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(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) } ///  /// Returns the unmanaged address of the given array. ///  ///  ///  if null, otherwise the address of the array [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