Access violation in winhttp.dll

I'm trying to perform an HTTP GET using WinHTTP in C++, but it's crashing at some point after resolving the name (after getting the WINHTTP_CALLBACK_STATUS_NAME_RESOLVED in the status callback function). I'm getting an access violation in winhttp.dll. The callstack is:

winhttp.dll!HTTP_USER_REQUEST::_IndicateSocketAddress() + 0x221ed bytes
winhttp.dll!HTTP_USER_REQUEST::OnDnsNameResolved() + 0x24 bytes
winhttp.dll!WEBIO_REQUEST::_OnInformation() + 0x1c0c bytes webio.dll!_WaIndicateHttpRequestInformation@16() + 0x15a bytes webio.dll!_WaHttpInformationConnection@16() + 0x7a bytes
webio.dll!_WapTcpDnsQueryCompletionRoutine@12() + 0x2f bytes
webio.dll!_WapCallDnsQueryCompletion@12() + 0x6d bytes webio.dll!_WaDnsResolutionWorker@8() + 0x157 bytes ntdll.dll!_TppSimplepExecuteCallback@8() + 0x7b bytes
ntdll.dll!TppWorkerThread@4() + 0x5a4 bytes
kernel32.dll!@BaseThreadInitThunk@12() + 0x12 bytes
ntdll.dll!__RtlUserThreadStart@8() + 0x27 bytes
ntdll.dll!__RtlUserThreadStart@8() + 0x1b bytes

Relevant code is:

enum OnlineState
{
    OnlineState_Idle,
    OnlineState_Registering
};

static OnlineState g_OnlineState = OnlineState_Idle;
HINTERNET g_Request = 0;
HINTERNET g_Connection = 0;
unsigned char g_HTTPBuffer[1024];

void HTTPRequestComplete()
{
    if(g_Request != 0)
    {
        WinHttpCloseHandle(g_Request);
        g_Request = 0;
    }
    if(g_Connection != 0)
    {
        WinHttpCloseHandle(g_Connection);
        g_Connection = 0;
    }
    g_OnlineState = OnlineState_Idle;
}

void HTTPAsyncCallback(HINTERNET hInternet, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInformation, DWORD dwStatusInformationLength)
{
    switch(dwInternetStatus)
    {
        case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE:
        {
            // Get the response
            if (!WinHttpReceiveResponse(g_Request, 0))
            {
            // Failed to get the response
                HTTPRequestComplete();
                return;
            }
        }
        break;

        case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE:
        {
            DWORD statusCode = 0;
            DWORD statusCodeSize = sizeof(DWORD);

            if (!WinHttpQueryHeaders(g_Request,
                           WINHTTP_QUERY_STATUS_CODE |     WINHTTP_QUERY_FLAG_NUMBER,
                           WINHTTP_HEADER_NAME_BY_INDEX,
                           &statusCode,
                           &statusCodeSize,
                           WINHTTP_NO_HEADER_INDEX))
            {
                // Failed to query headers
                HTTPRequestComplete();
                return;
            }

            if (HTTP_STATUS_OK != statusCode)
            {
                // Error status
                HTTPRequestComplete();
                return;
            }

            if (!WinHttpReadData(g_Request,
                           g_HTTPBuffer,
                           sizeof(g_HTTPBuffer),
                           0))
            {
                // Error reading data
                HTTPRequestComplete();
                return;
            }
        }
        break;

        case WINHTTP_CALLBACK_STATUS_READ_COMPLETE:
        {
            if (dwStatusInformationLength > 0)
            {
                // Store the data

                // Read the next data
                if (!WinHttpReadData(g_Request,
                                     g_HTTPBuffer, 
                                         sizeof(g_HTTPBuffer),
                                     0))
                {
                    // Error
                HTTPRequestComplete();
                return;
            }
        }
        else
        {
            // Request completed OK
            HTTPRequestComplete();
        }
    }
    break;

    default:
        break;
    }
}

// Online functionality
void Online_UpdateServer()
{
    switch(g_OnlineState)
    {
    case OnlineState_Idle:
        {
            // Get our local ip address by connecting a local socket to a web address and reading the socket name

            // Look up the address to connect to
            addrinfo hints;
            addrinfo* res = 0;
            memset(&hints, 0, sizeof hints);
            hints.ai_family = AF_UNSPEC;
            hints.ai_socktype = SOCK_DGRAM;
            getaddrinfo("www.google.com", "80", &hints, &res);

            // Create the socket
            int tempSocket = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
            unsigned int localAddress = 0;
            if (tempSocket >= 0)
            {
                // Connect the socket
                connect(tempSocket, res->ai_addr, res->ai_addrlen);

                // Get the socket name (our local ip address)
                sockaddr_in localName;
                memset(&localName, 0, sizeof(localName));
                int bufferSize = sizeof(localName);
                if(getsockname(tempSocket, (sockaddr*)&localName, &bufferSize) == 0)
                {
                    // Get the IP address
                    localAddress = localName.sin_addr.S_un.S_addr;
                }

                closesocket(tempSocket);
            }

            // Connect
            g_Connection = WinHttpConnect(g_Internet, L"www.google.com", INTERNET_DEFAULT_PORT, 0);

            // Open the request
            std::wstringstream urlString;
            urlString << L"/";
            std::wstring tempString = urlString.str();
            const wchar_t* wurlString = tempString.c_str();
            g_Request = WinHttpOpenRequest(g_Connection, 0, wurlString, 0, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0);

            // Install the status callback function.
            if(WINHTTP_INVALID_STATUS_CALLBACK == WinHttpSetStatusCallback(g_Request, (WINHTTP_STATUS_CALLBACK)HTTPAsyncCallback, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, NULL))
            {
                OutputDebugString(L"Error");
            }

            // Send the request
            if(!WinHttpSendRequest(g_Request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0))
            {
                OutputDebugString(L"Error");
            }

            // Log that we're registering
            g_OnlineState = OnlineState_Registering;
        }
        break;

    case OnlineState_Registering:
        {
            // Don't do anything, as we're currently registering
        }
        break;

    default:
        break;
    }
}

g_Internet is initialised like this:

// Initialise HTTP
g_Internet = WinHttpOpen(L"Boomba", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, WINHTTP_FLAG_ASYNC);

As far as I can tell, I'm initialising and using WinHTTP correctly, and everything seems to come back OK without errors. The callback is called twice, first time with WINHTTP_CALLBACK_STATUS_RESOLVING_NAME, then with WINHTTP_CALLBACK_STATUS_NAME_RESOLVED, then after that I get an access violation:

0xC0000005: Access violation reading location 0x00000014

The location changes, to various things, so I'm thinking it looks like it could possibly be a threading issue, but I'm not sure what could be the problem. Any ideas? (I'm running on Windows 7 64-bit).


    if (WINHTTP_INVALID_STATUS_CALLBACK == WinHttpSetStatusCallback(
       g_Request, 
       (WINHTTP_STATUS_CALLBACK)HTTPAsyncCallback,        // <=== evil
       WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 
       NULL))

The compiler originally complained about a mismatch between your function and the function pointer type that is required. You fixed the problem by shutting up the compiler with that cast. But that didn't actually fix the problem. Now you bought yourself a real problem, a corrupted stack. Very hard to diagnose.

The callback function must be declared as __stdcall, not the default __cdecl calling convention. The Windows headers use the CALLBACK macro for that. Fix:

 void CALLBACK HTTPAsyncCallback(/* etc*/)

And of course remove that cast.

链接地址: http://www.djcxy.com/p/95504.html

上一篇: 未处理的异常System.BadImageFormatException

下一篇: 在winhttp.dll中访问冲突