2011-10-31 6 views
3

Я использую CDB (отладчик консоли Microsoft) и WinDbg, чтобы попытаться заставить перерыв, когда разложение кучи происходит на P/Invoke в ReadFile. Я прочитал еще много байтов из текстового файла, чем то, что я выделил для массива chBuf. Отладчик не видит нарушения доступа до GC.Collect, что составляет слишком поздно для меня. Перед запуском моей программы я запускаюОбнаружить кучу коррупции ПЕРЕД сборкой мусора

gflags -p /enable testheap.exe /unaligned 

Эффект кажется бесполезным. Я написал эту небольшую тестовую программу, чтобы применить то, что я нахожу, для отладки гораздо более крупной коммерческой программы, которая имеет проблемы с кучей коррупции.

Я также пробовал DebugDiag с Application Verifier и MDA callbackOnCollectedDelegate без успеха. Разве мое использование gflags не должно быть обнаружено сразу после ReadFile?

Код:

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'.» В этом и заключается нарушение прав доступа. Как отладчик может видеть нарушение прав доступа до того, как оно произойдет?? Если вы имеете в виду, что коррупция не обнаружена до «GC.Collect», вам просто нужно искать коррупцию раньше, например, путем явного вызова «HeapValidate». –

+0

Raymond, нарушение доступа происходит до GC.Collect. Если я разорву и проведу проверку до GC, это показывает, что управляемая куча уже повреждена. Установка gflags должна поймать это. См. Поддержку Microsoft для Microsoft ID статьи: 286470. Это просто не работает для меня, как рекламируется. В моей коммерческой программе GC может произойти уже после кучи. Не следует ли исключать исключение в момент повреждения кучи? Почему тогда отладчик не поймал его? –

+0

Кроме того, Win32 HeapValidate не кажется полезным для проверки проблем с управляемой кучей. Как бы вы указали правильные аргументы в пользу использования этого? –

ответ

1

Только предположение, но я считаю, что неожиданное поведение GFLAGS вызвано этой линии:

byte[] chBuf = new byte[8];

Поскольку chBuf управляется с помощью CLR, GFLAGS не способный поместить шаблон заполнения после него, чтобы обнаружить переполнение буфера. Попробуйте изменить что:

IntPtr chBuf = Marshal.AllocHGlobal(8);

Так что вы будете выделять в неуправляемом куче. Gflags должен иметь возможность работать с этим. Кроме того, вам может понадобиться изменить подпись ReadFile для того, чтобы работать:

[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#, этот подход, вероятно, пропустит многие управляемые собственные пинвы в моем коде - например, в сторонних элементах управления, настраивая USB-связь, не говоря уже о переходах в коде Microsoft. –

+1

P/Invoked 'ReadFile', вероятно, проглатывает разрыв отладки, созданный с внутренней стороны. Попробуйте запустить образец проекта под отладчиком, чтобы проверить, может ли он обнаружить переполнение буфера при вызове 'ReadFile' ... Просто проверил этот подход на моей машине, и он работает. Хотя, я не знаю, возможно ли это с вашим более крупным проектом. –

+0

Ilian, пожалуйста, предоставьте более подробную информацию о том, как это сработало для вас. Вы запустили образец проекта выше? Я попробовал ваше предложение об управлении конфигурацией отладки и выпуска в Visual Studio 2005. Включена неуправляемая отладка проекта. Элемент меню «Отладка/исключение»: установить разрыв при «нарушении доступа к Win32» и CLR/System.AccessViolationException. Я запрашиваю 513 символов из текстового файла с chBuf размером 8. ReadFile сообщает 513 символов, которые читаются и продолжают. При попытке выполнить команду GC.Collect программа замерзает. Благодарю. –

Смежные вопросы