2011-10-31 1 views
3

CDB (Microsoft Console Debugger) 및 WinDbg을 사용하여 힙 손상이 발생했을 때 ReadFile에 P/Invoke을 강제로 중단하려고 시도했습니다. 나는 chBuf 배열에 할당 한 것보다 더 많은 바이트를 텍스트 파일에서 읽습니다. 디버거에서 GC.Collect 이후에 액세스 위반이 표시되지 않습니다. 이 너무 늦습니다.입니다. 내 프로그램을 실행하기 전에 나는 실행한다가비지 수집하기 전에 힙 손상을 검색하십시오.

gflags -p /enable testheap.exe /unaligned 

효과는 쓸데없는 것처럼 보인다. 나는이 작은 테스트 프로그램을 작성하여 힙 손상 문제가있는 훨씬 더 큰 상용 프로그램을 디버깅하는 데 적용했습니다.

Application Verifier 및 MDA callbackOnCollectedDelegate를 사용하여 DebugDiag를 성공적으로 사용해 보았습니다. 내 gflags의 사용은 ReadFile 직후 힙 손상을 감지하지 않습니까?

코드 : chBuf 이후

byte[] chBuf = new byte[8];

는 CLR에 의해 관리되지 GFLAGS :

namespace TestHeap 

    public partial class Form1 : Form 
    { 
     [DllImport("kernel32.dll", SetLastError = true)] 
     static extern SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess, 
      uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, 
      uint dwFlagsAndAttributes, IntPtr hTemplateFile); 

     [DllImport("kernel32.dll", SetLastError = true)] 
     static extern bool ReadFile(SafeFileHandle hFile, [Out] byte[] lpBuffer, 
      uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, IntPtr lpOverlapped); 

     string fileName = "testHeap.txt"; 
     const uint GENERIC_READ = 0x80000000; 
     const uint OPEN_EXISTING = 3; 
     SafeFileHandle sh; 
     byte[] chBuf = new byte[8]; 

     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void testBtn_Click(object sender, EventArgs e) 
     { 
      bool nStat; 
      uint bytesToRead = 1025; 
      uint bytesRead = 0; 

      if (!(nStat = ReadFile(sh, chBuf, bytesToRead, out bytesRead, IntPtr.Zero))) 
       Debug.Print("testBtn_Click error in ReadFile, nStat = {0}", nStat); 
      MessageBox.Show(string.Format("After ReadFile, bytesToRead = {0},\n bytes read = {1}", bytesToRead, bytesRead)); 
      GC.Collect(); 
      MessageBox.Show("testBtn_Click end, after GC.Collect"); 
     } 

     private void Form1_Load(object sender, EventArgs e) 
     { 
      sh = CreateFile(fileName, GENERIC_READ, 0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero); 
     } 
    } 
} 
+0

확실하지 않음 그것은 액세스 위반이 발생하는 지점입니다. 디버거에서 액세스 위반 *이 발생하기 전에 어떻게 볼 수 있습니까? 'GC.Collect'까지 손상이 발견되지 않았다는 것을 의미한다면,'HeapValidate'를 명시 적으로 호출하는 것처럼 손상을 더 빨리 찾아야합니다. –

+0

Raymond, GC.Collect보다 먼저 액세스 위반이 발생합니다. GC를 깨고! GC 전에 확인하면 관리 힙이 이미 손상되었음을 알 수 있습니다. gflags를 설정하면이를 잡아야합니다. Microsoft 지원 문서 ID : 286470을 참조하십시오. 광고 된대로 작동하지 않습니다. 내 상용 프로그램에서 GC가 힙 손상 후 오래 발생할 수 있습니다. 힙이 손상된 시점에 예외가 발생해서는 안됩니까? 디버거가 왜 그것을 잡을 수 없습니까? –

+0

또한 Win32 HeapValidate는 관리되는 힙 문제를 검사하는 데 유용하지 않습니다. 그것을 사용하기위한 올바른 주장을 어떻게 제시 할 것입니까? –

답변

1

그냥 추측하지만 예상치 못한 GFLAGS 동작이 라인으로 인해 생각 버퍼 오버런을 감지하기 위해 채우기 패턴을 넣을 수 있습니다. 그래서

IntPtr chBuf = Marshal.AllocHGlobal(8);

당신이 관리되지 않는 힙에 할당됩니다 :에 있음을 변경해보십시오. Gflags가이를 사용할 수 있어야합니다. 또한, 당신은 일에 그것을 위해 ReadFile의 서명을 변경해야 할 수도 있습니다 ". 디버거가 GC.Collect``때까지 액세스 위반이 표시되지 않습니다"당신이 무엇을 의미하는

[DllImport("kernel32.dll", SetLastError = true)] 
static extern bool ReadFile(SafeFileHandle hFile, [Out] IntPtr lpBuffer, 
uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, IntPtr lpOverlapped); 
+1

Ilian, 귀하의 제안에 감사드립니다. 나는 이것을 시도하고 어떤 예외도 던지지 않는다. 네이티브 힙에 버퍼 오버런이있을 경우 ReadFile은 단순히 0 바이트를 반환합니다.그러나 내 큰 상용 코드가 C#에 완전히 포함되어 있으므로이 방법을 사용하면 Microsoft 코드 내에서의 전환은 말할 것도없고 USB 통신 설정과 같은 타사 컨트롤에서와 같이 내 코드에서 네이티브 핀볼을 관리하지 못할 수 있습니다. –

+1

P/호출 된'ReadFile'은 아마도 네이티브 측에서 던져진 디버그 브레이크를 삼키고 있습니다. 디버거에서 샘플 프로젝트를 실행하여'ReadFile'이 호출되는 동안 버퍼 오버런을 감지 할 수 있는지 확인하십시오 ... 내 컴퓨터에서이 접근법을 체크하면 작동합니다. 비록 이것이 당신의 큰 프로젝트에서 가능할 지 모르겠지만. –

+0

Ilian,이 방법에 대한 자세한 내용을 제공해주십시오. 위의 샘플 프로젝트를 실행 했습니까? 귀하의 제안을 Visual Studio 2005에서 디버그 및 릴리스 구성을 실행하는 시도했다. 프로젝트 관리되지 않는 디버깅을 사용할 수 있습니다. 디버그/예외 메뉴 항목 : "Win32 access violation"및 CLR/System.AccessViolationException이 발생하면 break를 설정합니다. 나는 크기가 8 인 chBuf가있는 텍스트 파일에서 513자를 요청합니다. ReadFile은 513자를 읽고 계속보고합니다. GC.Collect 명령을 시도하면 프로그램이 멈 춥니 다. 감사. –