windows 在HeapAlloc()失败后调用GetLastError()是否可靠?

pkwftd7m  于 12个月前  发布在  Windows
关注(0)|答案(1)|浏览(143)

我最近看了一些在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()。谢谢。

mdfafbf1

mdfafbf11#

为了测试,[...]
您无法“测试”合同是否有效。
合同是。“
前提条件和后置条件的组合被称为 * 合约 实现 * 有权放松其前提条件并加强其后置条件。当这种情况发生时,它被称为 * 实现细节 *。
实施细节不是合同的一部分。
如果HeapAlloc的文档说明
应用程序无法呼叫GetLastError以取得延伸的错误信息。
那么这就是与其后置条件相关的合约。当HeapAlloc返回NULL时,不要调用GetLastError

相关问题