异步 ReadFile() 导致 运行 时间错误?
Asynchronous ReadFile() causing run-time errors?
我正在实现一个读取子进程输出的函数。我的程序一般是单线程的,我只用异步的API来实现读取超时(同步版本的ReadFile()
不可用)。我创建了一个 OVERLAPPED
结构,调用异步 ReadFile()
然后 WaitForSingleObject()
具有所需的超时时间。
读取函数完成后,MSVC 有时会报告:
Run-Time Check Failure #2 - Stack around the variable 'rdCount' was
corrupted.
我尝试了各种调试和修复它的方法。报告的变量只是函数中声明的最后一个变量。根据内存查看,函数WaitForSingleObject()
有时会出现写入三个DWORD,其中最后一个与rdCount
重叠,然后报告损坏。
… cc cc cc cc 00 00 00 00 00 00 00 00 0f 00 00 00 cc cc cc cc …
└ rdCount ┘
否则它只写入这些 DWORD 中的第一个,然后函数正确完成。
… cc cc cc cc 02 01 00 00 cc cc cc cc 00 00 00 00 cc cc cc cc …
└ rdCount ┘
有趣的是,当我添加一些大小至少为 48 字节的填充(参见 padding
数组)时,问题消失了,因为 00 00 00 00 0f 00 00 00
的写入发生在该数组中。
谁能解释一下?我是不是遗漏了什么或者 WinAPI 有什么问题?
函数主体如下(删除了日志记录和检查)。
HANDLE readFinishEvent = CreateEvent(
NULL, // default security attributes
TRUE, // manual-reset event
FALSE, // initial state is nonsignaled
NULL // unnamed
);
QByteArray response;
CHAR buffer[BufferSize];
OVERLAPPED ovl;
CHAR padding[48]; // <----------- ARTIFICIAL PADDING -----------
ZeroMemory(&ovl, sizeof(ovl));
ovl.hEvent = readFinishEvent;
DWORD rdCount;
if(ReadFile(rdPipe, buffer, BufferSize, &rdCount, &ovl) == FALSE)
{
WaitForSingleObject(readFinishEvent, ReadTimeoutMs);
rdCount = ovl.InternalHigh;
}
CloseHandle(readFinishEvent);
response = QByteArray(buffer, (int)rdCount);
return response;
WaitForSingleObject(readFinishEvent, ReadTimeoutMs);
哎呀,这是一个非常讨厌的错误,您很幸运能够得到诊断。永远,永远不要忽略 winapi 函数 return 值。当它 returns WAIT_TIMEOUT 时,这会严重失败。处理不当,忘记取消I/O操作
随机灾难在它实际完成时发生,稍后,驱动程序将垃圾喷射到 buffer
和 ovl
曾经所在的堆栈中。当您继续调用此函数时,您会得到诊断信息。但通常 any 函数的局部变量可能会损坏。极难诊断,给微软买根雪茄来实现 /RTC
当您获得除 WAIT_OBJECT_0 以外的任何其他 return 值时,您 必须 调用 CancelIo()。
我正在实现一个读取子进程输出的函数。我的程序一般是单线程的,我只用异步的API来实现读取超时(同步版本的ReadFile()
不可用)。我创建了一个 OVERLAPPED
结构,调用异步 ReadFile()
然后 WaitForSingleObject()
具有所需的超时时间。
读取函数完成后,MSVC 有时会报告:
Run-Time Check Failure #2 - Stack around the variable 'rdCount' was corrupted.
我尝试了各种调试和修复它的方法。报告的变量只是函数中声明的最后一个变量。根据内存查看,函数WaitForSingleObject()
有时会出现写入三个DWORD,其中最后一个与rdCount
重叠,然后报告损坏。
… cc cc cc cc 00 00 00 00 00 00 00 00 0f 00 00 00 cc cc cc cc …
└ rdCount ┘
否则它只写入这些 DWORD 中的第一个,然后函数正确完成。
… cc cc cc cc 02 01 00 00 cc cc cc cc 00 00 00 00 cc cc cc cc …
└ rdCount ┘
有趣的是,当我添加一些大小至少为 48 字节的填充(参见 padding
数组)时,问题消失了,因为 00 00 00 00 0f 00 00 00
的写入发生在该数组中。
谁能解释一下?我是不是遗漏了什么或者 WinAPI 有什么问题?
函数主体如下(删除了日志记录和检查)。
HANDLE readFinishEvent = CreateEvent(
NULL, // default security attributes
TRUE, // manual-reset event
FALSE, // initial state is nonsignaled
NULL // unnamed
);
QByteArray response;
CHAR buffer[BufferSize];
OVERLAPPED ovl;
CHAR padding[48]; // <----------- ARTIFICIAL PADDING -----------
ZeroMemory(&ovl, sizeof(ovl));
ovl.hEvent = readFinishEvent;
DWORD rdCount;
if(ReadFile(rdPipe, buffer, BufferSize, &rdCount, &ovl) == FALSE)
{
WaitForSingleObject(readFinishEvent, ReadTimeoutMs);
rdCount = ovl.InternalHigh;
}
CloseHandle(readFinishEvent);
response = QByteArray(buffer, (int)rdCount);
return response;
WaitForSingleObject(readFinishEvent, ReadTimeoutMs);
哎呀,这是一个非常讨厌的错误,您很幸运能够得到诊断。永远,永远不要忽略 winapi 函数 return 值。当它 returns WAIT_TIMEOUT 时,这会严重失败。处理不当,忘记取消I/O操作
随机灾难在它实际完成时发生,稍后,驱动程序将垃圾喷射到 buffer
和 ovl
曾经所在的堆栈中。当您继续调用此函数时,您会得到诊断信息。但通常 any 函数的局部变量可能会损坏。极难诊断,给微软买根雪茄来实现 /RTC
当您获得除 WAIT_OBJECT_0 以外的任何其他 return 值时,您 必须 调用 CancelIo()。