2016-02-10 31 views
5

ナイトリービルドマシン上に構築されたアプリケーションに障害が発生したが、他のデスクトップ上で正常に動作します。バイナリは、Windows Server 2012上で動作しないWindows Server 2012の

例外の種類 "保護されたメモリを読み書きしようとしましたが、これは他のメモリが壊れていることを示していることがよくあります。スローされます。

WindowsServer2012マシン全体でリモートデバッグを使用してデバッグしてマシンを構築すると、この例外がkernel32コールHeapSizeがコード内で作成された場所でスローされることがわかります。ここでHeapSizeがインポートと呼ばれる方法です。

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

これは危険なクラスのコンストラクタの一部として呼び出されます。不足しているとどのようにこの問題を解決することができるもので

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

任意の手がかり?

これは私がWindbgの中で見たものである。

This is what I see in Windbg

EventLogには示しています

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

あなたはヒープサイズを呼び出すためのPInvokeを使用していますか?メソッド宣言を表示できますか? (また、すべてのマシンはつまり、x64の対x86の同じアーキテクチャです?) – stuartd

+1

は、クラッシュダンプを取る[windbgの+ SOS](https://blogs.msdn.microsoft.com/kaevans/2011/04でそれで突きます/ 11/intro-to-windbg-for-net-developers /) –

+0

はい構成は同じです。両方のマシンがx64で、コードがx64構成で構築されています。 コードは次のとおりです。 [DllImport( "kernel32")] static extern int HeapSize(int hHeap、int flags、void * block); //メモリブロックのサイズを返します。 public static int SizeOf(void * block) { int result = HeapSize(ph、0、block); if(result == -1)新しいInvalidOperationException()をスローします。戻り値: ; } – NVK

答えて

2

あなたが書いたコードが今まで働いているべきではありません。

HeapSizeは、ヒープのサイズ、たとえばHeapAllocを呼び出して割り当てられたものを返します。

lpMemサイズ関数が取得するメモリブロックへのポインタ

[IN]:HeapSizeに提供ポインタがHeapAllocを呼び出すことによって返されたポインタでなければなりません。これは、HeapAllocまたはHeapReAlloc関数によって返されるポインタです。

あなたはHeapSizeを呼び出しますが、そのヒープ内のどこにでも可能性があり、ポインタを提供しています。あるいは全くないことヒープに:

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

だけでなくMarshal.StringToHGlobalAnsi()ヒープ自体へのポインタどこか、ヒープ内のポインタを返し、ない、あなたもポインタが割り当てられたヒープを知らないだろうプロセスが複数のヒープを割り当てられる可能性があるからです。

あなたがこの機能の目的の根本的な誤解を持って表示されますので、すべてのことは、重要ではありません - あなたは、ヒープ内で作られた割り当てのサイズを取得するためにそれを使用しているように見えます。 Marshal.StringToHGlobalAnsi()によって返されたメモリは、HeapAlloc()(ヒープではないため)を呼び出すことによって割り当てられません。AllocHGlobalを呼び出して割り当てられます。

Marshal.StringToHGlobal()のドキュメントから:

このメソッドは常にFreeHGlobalを呼び出してメモリを解放、文字列のために必要なアンマネージメモリを割り当てているので、それによって割り当てられたメモリはMarshal.FreeHGlobal()を呼び出して解放する必要があります。

このMarshal方法はHeapAllocHeapSizeまたは関連機能とは何の関係もありません。

Marshal.StringToHGlobal()によって返されたポインタのメモリ割り当てのサイズを調べたい場合は、source of the the Marshal classを調べ、win32関数LocalAllocを使用していることがわかります。とてもLocalAllocが実際に割り当てのサイズを見つけるために使用することができ姉妹機能LocalSizeを、持っていることが起こります。

しかし、.NET Frameworkが、それはLocalAllocを使い続けるだろうという保証を提供していないので、そうすることが、将来的に動作することを保証するものではありません。変更した場合は、内部のLocalSizeが機能しなくなる可能性があります。

...

すべてのことは言った:

私はこれのいずれかは、あなたがもう一度あなたのコードを見てみると、最初の場所で

を行うにはどのような意味であるとは思わない:

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

あなたはあなたに戻っANSI文字列の長さを見つけるためにしようとしています。

この業務のすべてはHeapSizeまたはLocalSizeとは全く関係ありません。

'ansi'文字列の長さを探したい場合は、単純な文字列長を実装するか、すでに実装されているものを使用するだけです。

次のプログラムは、Marshal.StringToHGlobal()を使用し、印刷物:

文字列: 'こんにちは';長さ: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; 
    } 
関連する問題