Удаление ptr разрешается в исключении нарушения доступа, записывающем в 0 - PullRequest
0 голосов
/ 22 марта 2011

Я получил следующий код, в котором в последнем утверждении я пытаюсь удалить указатель на динамически создаваемую память.

Но как только я получаю инструкцию, возникает исключение нарушения прав доступа:

Необработанное исключение в 0x0094c91f в Server.exe: 0xC0000005: Место чтения нарушения доступа 0x00000000.

Но когда я прохожу через него с помощью отладчика, он содержит действительный адрес с допустимыми данными в нем... я не понимаю, что я делаю здесь неправильно ...

Есть предложения?

void CServer::HandleAcceptRequest(ACCEPT_REQUEST* pRequest)
{
    //Add the new connection socket to the connection handler
    m_pConnectionHandler->AddConnection(pRequest->m_NewConnection);
    //Associate the new connections´ socket handle with the IOCP
    if(!m_pCompletionPort->AssociateHandle((HANDLE)pRequest->m_NewConnection, 0))
    {
        MessageBox(NULL, "Could not associate a socket handle with the completion port", "", MB_ICONERROR | MB_OK);
        DebugBreak();
    }


    //Create a new COMM_REQUEST and initialize a Recv-Request
    COMM_REQUEST* pCommRequest = new COMM_REQUEST;
    memset(pCommRequest, 0, sizeof(COMM_REQUEST));
    pCommRequest->Socket = pRequest->m_NewConnection;
    pCommRequest->m_RequestType = BASIC_REQUEST::RECV;

    WSABUF* buf = new WSABUF;
    buf->buf = pCommRequest->cBuf;
    buf->len = Inc::COMMUNICATION_BUFFER_SIZE;
    DWORD dwFlags = 0;
    if(WSARecv(pCommRequest->Socket, buf, 1, NULL, &dwFlags, pCommRequest, NULL))
    {
        DWORD dwRet = WSAGetLastError();
        if(dwRet != WSA_IO_PENDING)
        {
            MessageBox(NULL, "WSARecv() failed", "", MB_ICONERROR | MB_OK);
            DebugBreak();
        }
    };

    //Delete the old ACCEPT_REQUEST structure
    delete pRequest;
}

РЕДАКТИРОВАТЬ: Я выделил памятьв другой функции в главном потоке

bool CConnectionHandler::AcceptNewConnection(SOCKET ListenSocket, unsigned nCount)
{
    DWORD dwBytesReceived = 0;
    ACCEPT_REQUEST* pOverlapped = nullptr;

    for(unsigned n = 0; n < nCount; n++)
    {
        dwBytesReceived = 0;
        pOverlapped = new ACCEPT_REQUEST;
        memset(pOverlapped, 0, sizeof(ACCEPT_REQUEST));
        pOverlapped->m_RequestType = ACCEPT_REQUEST::ACCEPT;

        //add the ListenSocket to the request
        pOverlapped->m_ListenSocket = ListenSocket;
        //invalidate the new connection socket
        pOverlapped->m_NewConnection = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if(pOverlapped->m_NewConnection == INVALID_SOCKET)
        {
            delete pOverlapped;
            return false;
        }

        // call 'AcceptEx'
        if(m_lpfnAcceptEx(pOverlapped->m_ListenSocket, pOverlapped->m_NewConnection, pOverlapped->cOutputBuffer, 0, sizeof(sockaddr_in) + 16, sizeof(sockaddr_in) + 16, &dwBytesReceived, pOverlapped) == FALSE)
        {
            DWORD dwRet = WSAGetLastError();
            if(dwRet == ERROR_IO_PENDING)
                continue;
            else
                return false;
        }
    }

    return true;
};

EDIT2: код потоков, связанный с передачей параметра в функцию ...

unsigned int WINAPI ServerThreadFunc(void* pvArgs)
{
    CServer* pServer = (CServer*)pvArgs;        // pointer to the server object
    DWORD dwBytes = 0;
    ULONG_PTR ulKey;
    OVERLAPPED* pOverlapped = nullptr;
    bool bLooping = true;

    while(bLooping)
    {
        //TODO: Add code (ServerThreadFunc)
        if(!pServer->m_pCompletionPort->GetCompletionStatus(&dwBytes, &ulKey, &pOverlapped, INFINITE))
        {
            //TODO: Set some error variable or flag an error event to notify the main thread
            DebugBreak();
        }

        //check type of request
        switch(((BASIC_REQUEST*)pOverlapped)->m_RequestType)
        {
        case BASIC_REQUEST::ACCEPT:
            {
                // TODO: Handle AcceptEx-request
                pServer->HandleAcceptRequest(static_cast<ACCEPT_REQUEST*>(pOverlapped));

Ответы [ 2 ]

1 голос
/ 22 марта 2011

Извините, по-настоящему ничего не понять из предоставленных вами кусочков.

Однако в третьем фрагменте кода у вас есть этот вызов

pServer->HandleAcceptRequest(static_cast<ACCEPT_REQUEST*>(pOverlapped));

Этот вызов уничтожит объект *pOverlapped, вызвав на него delete. (Помните, что в самом конце HandleAcceptRequest вы делаете delete pRequest, где pRequest - это параметр HandleAcceptRequest).

Это сделает pOverlapped висящим указателем, который указывает на мертвую память. Я не вижу в вашем коде места, где бы вы повторно инициализировали этот висячий указатель или установили его на ноль.

Если вы не инициализируете его повторно, то при следующем доступе к *pOverlapped в цикле будет получен доступ к мертвой памяти (которая может показаться «работающей»), а при следующей попытке к delete это снова будет, скорее всего, авария. Если следующая попытка delete снова будет предпринята в конце HandleAcceptRequest, то поведение, вероятно, будет точно таким, как вы первоначально описали.

0 голосов
/ 22 марта 2011
OVERLAPPED* pOverlapped = nullptr;
..
pServer->m_pCompletionPort->GetCompletionStatus(&dwBytes, &ulKey, &pOverlapped, INFINITE);

Ок.Кажется, вы удаляете неправильный указатель.Тот, который вы удаляете из HandleAcceptRequest (), больше не является указателем на OVERLAPPED, так как указатель был преобразован из OVERLAPPED * в ACCEPT_REQUEST *.

Является ли GetCompletionStatus () вашим собственным?

...