2016-02-10 19 views
5

Un'applicazione costruita su computer di compilazione notturna non funziona su Windows Server 2012 ma funziona correttamente su altri desktop.I file binari creati su Windows 7 non riescono su Windows Server 2012

Un'eccezione del tipo "Tentativo di leggere o scrivere memoria protetta. Ciò è spesso un'indicazione che altra memoria è corrotta." viene lanciato

Quando eseguo il debug utilizzando il debug remoto sul computer WindowsServer2012 e sulla macchina di compilazione, vedo che questa eccezione viene generata in un punto in cui il codice 3232 chiama HeapSize nel codice. Ecco come HeapSize viene importato e chiama:

[DllImport("kernel32")] 
static extern int HeapSize(int hHeap, int flags, void* block); 
// Returns the size of a memory block. 

public static int SizeOf(void* block) 
{ 
    int result = HeapSize(ph, 0, block); 
    if (result == -1) throw new InvalidOperationException(); 
    return result; 
} 

Questo è chiamato come parte di costruttore di una classe non sicuro:

public UnManagedBuffer(StringBuilder sb) 
    { 
     PtrStart = (byte*)Marshal.StringToHGlobalAnsi(sb.ToString()); 
     Size = UnManagedMemory.SizeOf(PtrStart); 
     PtrWriteNextValue = PtrStart + Size - 1; 
     PtrReturnNextValue = PtrStart; 
    } 

Degli indizi su quello che potrebbe essere mancante e come risolvere questo problema?

Questo è quello che vedo in Windbg:

This is what I see in Windbg

EventLog mostra:

Log Name:  Application 
    Source:  .NET Runtime 
    Level:   Error 
    Keywords:  Classic 
    Description: 
Application: TestEngine.exe 
Framework Version: v4.0.30319 
Description: The process was terminated due to an unhandled exception. 
Exception Info: System.AccessViolationException 
    at Core.Utils.UnManagedMemory.HeapSize(Int32, Int32, Void*) 
    at Core.Utils.UnManagedMemory.SizeOf(Void*) 
    at Core.Utils.UnManagedBuffer..ctor</Event> 

Faulting application name: TestEngine.exe, version: 1.0.0.0, time stamp: 0x56b532bb 
Faulting module name: ntdll.dll, version: 6.3.9600.18185, time stamp: 0x5683f0c5 
Exception code: 0xc0000005 
Fault offset: 0x0000000000057306 
Faulting process id: 0x2eb8 
Faulting application start time: 0x01d164e45b12d7dd 
Faulting application path: C:\NGDLM\Lib\TestEngine.exe 
Faulting module path: C:\Windows\SYSTEM32\ntdll.dll 
Report Id: bea6eb89-d0d7-11e5-80eb-0050568cd888 
Faulting package full name: 
Faulting package-relative application ID: 
+0

Si sta utilizzando PInvoke chiamare HEAPSIZE? Puoi mostrare la dichiarazione del metodo? (Inoltre, tutte le macchine hanno la stessa architettura, cioè x86 vs x64?) – stuartd

+1

Fai un crash dump, colpiscilo con [windbg + SOS] (https://blogs.msdn.microsoft.com/kaevans/2011/04/11/intro-to-windbg-per-net-developers /) –

+0

Sì, la configurazione è la stessa: entrambe le macchine sono x64 e il codice è costruito in x64 config. Il codice è: [DllImport ("kernel32")] statico extern int HeapSize (int hHeap, int flags, void * block); // Restituisce la dimensione di un blocco di memoria. public static int SizeOf (void * block) { int result = HeapSize (ph, 0, block); if (result == -1) lanciare InvalidOperationException(); risultato di ritorno; } – NVK

risposta

2

Il codice che hai scritto non avrebbe dovuto mai lavorato.

HeapSize restituisce la dimensione di un heap, ad esempio, qualcosa allocato chiamando HeapAlloc. Il puntatore fornito HeapSize deve essere il puntatore restituito chiamando HeapAlloc:

lpMem [a]

Un puntatore al blocco di memoria la cui dimensione la funzione otterrà. Questo è un puntatore restituito dalla funzione HeapAlloc o HeapReAlloc.

si sta chiamando HeapSize, ma fornendo un puntatore che potrebbe essere ovunque all'interno di quel mucchio; o no in quel mucchio a tutti:

PtrStart = (byte*)Marshal.StringToHGlobalAnsi(sb.ToString()); 
    Size = UnManagedMemory.SizeOf(PtrStart); 
    PtrWriteNextValue = PtrStart + Size - 1; 
    PtrReturnNextValue = PtrStart; 

Non solo Marshal.StringToHGlobalAnsi() restituire un puntatore da qualche parte nel mucchio, e non un puntatore al mucchio stesso, non sa nemmeno che mucchio il puntatore sono stati stanziati da, perché il processo potrebbe avere più heap allocati.

Tutto ciò non ha importanza, perché sembra che tu abbia un malinteso fondamentale sullo scopo di questa funzione: sembra che tu stia usando per recuperare la dimensione di un'allocazione effettuata all'interno di un heap. La memoria restituita da Marshal.StringToHGlobalAnsi() non viene assegnata chiamando lo HeapAlloc() (perché non è un heap!), Viene allocata chiamando lo AllocHGlobal.La memoria allocata da esso deve essere liberata chiamando Marshal.FreeHGlobal():

Dalla documentazione Marshal.StringToHGlobal() s':

Poiché questo metodo alloca la memoria non gestita necessaria per una stringa, liberare sempre la memoria chiamando FreeHGlobal.

Questo metodo Marshal non ha nulla a che fare con HeapAlloc, HeapSize o correlati funzioni.

Se avete in realtà vuole scoprire la dimensione della allocazione di memoria del puntatore restituito da Marshal.StringToHGlobal(), si potrebbe scavare attraverso la source of the the Marshal class e scoprire che utilizza la funzione Win32 LocalAlloc. Accade che lo LocalAlloc abbia una funzione sorella LocalSize, che può essere effettivamente utilizzata per trovare la dimensione di un'allocazione.

Tuttavia, non vi è alcuna garanzia che ciò avvenga in futuro, poiché la struttura .Net non garantisce che continuerà a utilizzare LocalAlloc. Se hanno cambiato l'interno LocalSize potrebbe smettere di funzionare.

...

tutto ciò detto:

non credo che niente di tutto questo è ciò che si intende fare, in primo luogo

Guardando il codice di nuovo:

PtrStart = (byte*)Marshal.StringToHGlobalAnsi(sb.ToString()); 
    Size = UnManagedMemory.SizeOf(PtrStart); 
    PtrWriteNextValue = PtrStart + Size - 1; 
    PtrReturnNextValue = PtrStart; 

Si sta cercando di trovare la lunghezza della stringa ansi restituita.

Tutte queste attività di HeapSize o LocalSize sono completamente irrilevanti.

Se si desidera trovare la lunghezza di una stringa 'ansi', è sufficiente implementare una lunghezza di stringa semplice stupida o utilizzare una delle implementazioni già disponibili per l'utente.

Il seguente programma utilizza Marshal.StringToHGlobal() e stampe:

stringa: 'Ciao'; Lunghezza: 5

public static void Main(string[] args) 
    { 
     IntPtr strPtr = IntPtr.Zero; 
     string str = "Hello"; 
     try 
     { 
      strPtr = Marshal.StringToHGlobalAnsi(str); 

      Console.Out.WriteLine("String: '{0}'; Length: {1}", str, AnsiStrLen(strPtr)); 
     } 
     finally 
     { 
      if(strPtr != IntPtr.Zero) 
      { 
       Marshal.FreeHGlobal(strPtr); 
      } 
     } 
    } 

    public static int AnsiStrLen(IntPtr strPtr) 
    { 
     int size = 0; 

     while(Marshal.ReadByte(strPtr) != 0) 
     { 
      size++; 
      strPtr = IntPtr.Add(strPtr, 1); 
     } 

     return size; 
    }