2016-02-10 13 views
5

Eine Anwendung, die auf einem nächtlichen Buildcomputer erstellt wurde, funktioniert unter Windows Server 2012 nicht, funktioniert aber auf anderen Desktops einwandfrei.Unter Windows 7 erstellte Binärdateien schlagen unter Windows Server 2012 fehl

Eine Ausnahme der Art "Versuch, geschützten Speicher zu lesen oder zu schreiben. Dies ist oft ein Hinweis darauf, dass anderer Speicher beschädigt ist." ist geworfen.

Wenn ich debuggen mit remote-Debugging über die WindowsServer2012 Maschine und Maschine zu bauen, sehe ich, dass diese Ausnahme an einer Stelle ausgelöst wird, wo Kernel32 Aufruf HeapSize im Code gemacht wird. Hier wird, wie HeapSize wird importiert und rief:

[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; 
} 

Dies als Teil einer unsicheren Klasse Konstruktor aufgerufen wird:

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

Irgendwelche Hinweise auf das, was fehlen könnte und wie diese zu beheben?

Dies ist, was ich in Windbg sehen:

This is what I see in Windbg

EventLog zeigt:

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

Sind Sie PInvoke mit HeapSize anrufen? Können Sie die Methodendeklaration anzeigen? (Sind auch alle Maschinen die gleiche Architektur, dh x86 vs x64?) – stuartd

+1

Nehmen Sie einen Absturzspeicherplatz, stoßen Sie ihn mit [windbg + SOS] an (https://blogs.msdn.microsoft.com/kaevans/2011/04/11/intro-to-windbg-fuer-net-entwickler /) –

+0

Ja Konfiguration ist die gleiche - beide Maschinen sind x64 und Code ist in x64-Konfig gebaut. Der Code lautet: [DllImport ("kernel32")] statisch extern int HeapSize (int hHeap, int flags, void * block); // Gibt die Größe eines Speicherblocks zurück. public static int GrößeOf (void * Block) { int Ergebnis = HeapSize (ph, 0, Block); if (result == -1) neue InvalidOperationException() werfen; Ergebnis zurückgeben; } – NVK

Antwort

2

Der Code, den Sie sollten nicht immer gearbeitet geschrieben habe.

HeapSize gibt die Größe eines Heaps zurück, z. B. etwas, das durch Aufrufen von HeapAlloc zugeordnet wurde.

lpMem [in]

Ein Zeiger auf den Speicherblock, deren Größe die Funktion wird erhalten: Der Zeiger auf HeapSize muss mit den Zeiger durch Aufrufe HeapAlloc zurückgegeben werden. Dies ist ein Zeiger, der von der HeapAlloc- oder HeapReAlloc-Funktion zurückgegeben wird.

Du nennst HeapSize, sondern einen Zeiger bereitstellt, die in diesem Haufen überall sein könnte; oder gar nicht in diesem Haufen:

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

Nicht nur Marshal.StringToHGlobalAnsi() einen Zeiger irgendwo auf der Halde, und nicht einen Zeiger auf dem Heap selbst, die Sie nicht einmal wissen, die den Zeiger Haufen wurde zugewiesen von, weil der Prozess mehrere zugewiesene Heaps haben könnte.

All dies ist egal, weil es scheint, dass Sie ein grundlegendes Missverständnis über den Zweck dieser Funktion haben - Sie scheinen es zu verwenden, um die Größe einer Zuweisung innerhalb eines Heaps abgerufen. Der von Marshal.StringToHGlobalAnsi() zurückgegebene Speicher wird nicht zugewiesen, indem HeapAlloc() aufgerufen wird (da es kein Heap ist), es wird zugewiesen, indem aufruft.Der Speicher, der von ihm zugeordneten muss von Marshal.FreeHGlobal() Aufruf befreit werden:

Von Marshal.StringToHGlobal() ‚s Dokumentation:

Da diese Methode des nicht verwalteten Speicher reserviert für eine Zeichenfolge erforderlich, immer den Speicher frei von FreeHGlobal aufrufen.

Diese Marshal Methode hat nichts mit HeapAlloc, HeapSize oder verwandten Funktionen zu tun.

Wenn Sie tatsächlich auf die Größe der Speicherzuordnung des von Marshal.StringToHGlobal() zurückgegebene Zeiger herausfinden wollte, könnte man durch die source of the the Marshal class graben und finden Sie heraus, dass es die win32 Funktion LocalAlloc verwendet. Es kommt vor, dass LocalAlloc eine Schwesterfunktion LocalSize hat, die tatsächlich verwendet werden kann, um die Größe einer Zuordnung zu finden.

Es kann jedoch nicht garantiert werden, dass dies auch in Zukunft funktioniert, da das .Net-Framework keine Garantie dafür gibt, dass es auch weiterhin verwendet. Wenn sie die Interna geändert haben, LocalSize funktioniert möglicherweise nicht mehr.

...

All das sagte:

Ich glaube nicht, irgendetwas davon ist, was Sie

Blick auf den Code wieder in erster Linie zu tun bedeutete:

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

Sie versuchen, die Länge der zurückgegebenen Ansi-Zeichenfolge zu finden.

All dies Geschäft von HeapSize oder LocalSize ist völlig irrelevant.

Wenn Sie nur die Länge einer 'Ansi'-Zeichenfolge finden möchten, müssen Sie nur eine dumme einfache Zeichenfolge Länge implementieren, oder verwenden Sie eine der Implementierungen bereits für Sie da.

Das folgende Programm verwendet Marshal.StringToHGlobal() und druckt:

String: 'Hallo'; Länge: 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; 
    }