Windows XP 64位上的GetTokenInformation的意外行为

时间:2014-06-01 04:30:48

标签: c++ windows winapi

我很好奇,如果我在理解API时遗漏了一些东西,那么应首先用NULL参数调用以检索所需的缓冲区大小,然后在分配缓冲区后再次调用它们。

我的理解是这个缓冲区长度不会从第一次调用变为第二次。 (好吧,假设我们没有处于“竞争状态”的情况,这是另一个故事。)

所以这是一个简单的现实生活中的例子,我在Windows XP SP2(64位)上观察到。以下方法获取当前用户的SID:

HANDLE hToken;
if(OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &hToken))
{
    DWORD dwSize = 0;
    if(!GetTokenInformation(hToken, TokenUser, NULL, dwSize, &dwSize) &&
        ::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
    {
        BYTE* pb = new (std::nothrow) BYTE[dwSize];
        if(pb)
        {
            TOKEN_USER* pTU = (TOKEN_USER*)pb;
            DWORD dwSize2;
            if(GetTokenInformation(hToken, TokenUser, pTU, dwSize, &dwSize2) &&
                dwSize == dwSize2)
            {
                LPWSTR pName;
                if(ConvertSidToStringSid(pTU->User.Sid, &pName))
                {
                    //Got it!
                    _tprintf(L"User SID=%s\n", pName);

                    LocalFree(pName);
                }
            }

            delete[] pb;
        }
    }

    CloseHandle(hToken);
}

我在第二次调用dwSize == dwSize2GetTokenInformation所做的那一部分,因为dwSize从第一次调用44返回GetTokenInformation而失败了},然后dwSize2从第二次调用返回为36

这种行为是否正常?

2 个答案:

答案 0 :(得分:2)

在检索所需的字节大小时,API返回更大的值并不是闻所未闻(可能是为了对齐目的而将其舍入等),然后在检索实际时返回较小的值时使用相同的API数据,因为它报告实际写入分配的内存中的字节数。您不必比较这两个大小,相信如果函数说它成功了,那么写入的大小是< =分配的大小。

如果您担心会改变所需字节大小的竞争条件,请使用循环分配内存直到成功:

HANDLE hToken;
if (OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &hToken))
{
    BYTE* pb = NULL;
    DWORD dwSize = 0;
    TOKEN_USER* pTU = NULL;
    BOOL bRet;

    do
    {
        bRet = GetTokenInformation(hToken, TokenUser, pTU, dwSize, &dwSize);
        if (bRet)
            break;

        if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER)
            break;

        delete[] pb;
        pb = new (std::nothrow) BYTE[dwSize];
        if (!pb)
            break;

        pTU = (TOKEN_USER*)pb;
    }
    while (true);

    if (bRet)
    {
        // use pTU as needed...
    }

    delete[] pb;
    CloseHandle(hToken);
}

答案 1 :(得分:1)

只要dwSize大于dwSize2,就应该没问题。