我最近看了一些在HeapAlloc()
失败后调用GetLastError()
的代码。但是,根据HeapAlloc function的MSDN文档:
如果函数失败,它不会调用SetLastError。应用程序无法调用GetLastError以获取扩展错误信息。
互联网上到处都是在HeapAlloc()
失败后调用GetLastError()
的代码片段,我假设大多数编码人员(包括我自己)都被编程为在API失败时自然地调用GetLastError()
。
为了测试,我创建了这个例子来分配最大内存量:
#include <windows.h>
#include <stdio.h>
#include <stdint.h>
int main() {
HANDLE hHeap = GetProcessHeap();
if (hHeap == NULL) {
printf("Failed to get the process heap.\n");
return 1;
}
SetLastError(0); // Clear the last error
// Attempt to allocate a very large amount of memory
SIZE_T largeSize = SIZE_MAX;
LPVOID pMemory = HeapAlloc(hHeap, 0, largeSize);
if (pMemory == NULL) {
DWORD dwError = GetLastError();
printf("HeapAlloc failed: ");
switch (dwError) {
case ERROR_NOT_ENOUGH_MEMORY:
printf("Not enough memory available.\n");
break;
case ERROR_OUTOFMEMORY:
printf("Insufficient memory to satisfy the request.\n");
break;
default:
printf("Error code: %lu\n", dwError);
}
}
else {
printf("Memory allocation successful.\n");
HeapFree(hHeap, 0, pMemory);
}
return 0;
}
字符串
输出显示:
HeapAlloc失败:内存不足。
问题
为什么GetLastError()
看起来可以工作?这只是运气,所以每个人都应该避免调用它,因为依赖GetLastError()
获取详细的错误信息可能不可靠?
更新
HeapAlloc()
的官方文档说明:
如果函数失败,它不会调用SetLastError。应用程序无法调用GetLastError以获取扩展错误信息。
但是,从下面的注解来看,HeapAlloc()
的内部实现更新了TEB中的LastErrorValue
,但没有为外部开发人员提供文档。
下面是HeapAlloc
在TEB中用ERROR_NOT_ENOUGH_MEMORY
8更新LastErrorValue
的示例。
#include <windows.h>
#include <stdio.h>
#include <stdint.h>
#include <intrin.h>
typedef struct _MY_TEB {
// The TEB is highly stable across Windows versions.
uint8_t Padding[0x68];
ULONG LastErrorValue;
// ...
} MY_TEB;
int main() {
SetLastError(0);
printf("LastErrorValue (TEB): %lu\n", ((MY_TEB*)__readgsqword(0x30))->LastErrorValue);
printf("GetLastError (API): %lu\n", GetLastError());
HeapAlloc(GetProcessHeap(), 0, SIZE_MAX);
printf("LastErrorValue (TEB): %lu\n", ((MY_TEB*)__readgsqword(0x30))->LastErrorValue);
printf("GetLastError (API): %lu\n", GetLastError());
return 0;
}
型
其输出
LastErrorValue (TEB): 0
GetLastError (API): 0
LastErrorValue (TEB): 8
GetLastError (API): 8
型
总之,我将坚持使用官方文档,不调用GetLastError()
。谢谢。
1条答案
按热度按时间mdfafbf11#
为了测试,[...]
您无法“测试”合同是否有效。
合同是。“
前提条件和后置条件的组合被称为 * 合约 。 实现 * 有权放松其前提条件并加强其后置条件。当这种情况发生时,它被称为 * 实现细节 *。
实施细节不是合同的一部分。
如果
HeapAlloc
的文档说明应用程序无法呼叫
GetLastError
以取得延伸的错误信息。那么这就是与其后置条件相关的合约。当
HeapAlloc
返回NULL
时,不要调用GetLastError
。