我正在使用CDB(Microsoft控制台调试程序)和WinDbg尝试在P/Invoke将堆损坏发生到ReadFile时强制中断。我从文本文件中读取的字节比我分配给chBuf数组的字节多得多。调试器在GC.Collect
之后才会看到访问冲突,对我来说太晚。在运行我的程序之前,我运行
gflags -p /enable testheap.exe /unaligned
效果似乎毫无用处。我编写了这个小测试程序来应用我发现的调试更大的商业程序,这个程序存在堆腐败问题。
我还尝试使用Application Verifier和MDA callbackOnCollectedDelegate调试DebugDiag但没有成功。我是否使用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 :(得分: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);