删除 ptr 将解决写入 0 的访问冲突异常

发布于 2024-10-24 21:07:45 字数 3830 浏览 5 评论 0原文

我得到以下代码,其中最后一条语句我尝试删除指向动态创建的内存的指针。

但是,一旦我到达指令,就会引发访问冲突异常,并显示:

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;
};

编辑2:与向函数提供参数有关的线程代码...

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));

I got the following code in which last statement I try to delete a pointer to dynamically created memory.

But as soon as I get to the instruction a Access Violation exception is raised saying :

Unhandled exception at 0x0094c91f in
Server.exe: 0xC0000005: Access
violation reading location 0x00000000.

But when I step through it with the debugger it contains a valid address with valid data in it... I don't realize what I'm doing fatally wrong here...

Any suggestions?

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;
}

EDIT: I did allocate the memory in another function in the main thread

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: the threads code to do with giving the parameter to the function...

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));

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

橘和柠 2024-10-31 21:07:45

抱歉,无法从您提供的零碎内容中真正弄清楚任何内容。

但是,在第三段代码中,您有此调用。

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

此调用将通过调用 delete 来销毁 *pOverlapped 对象。 (请记住,在 HandleAcceptRequest 的最后,您要删除 pRequest,其中 pRequestHandleAcceptRequest 的参数) 。

这将使 pOverlapped 成为指向死内存的悬空指针。我在代码中没有看到任何地方可以重新初始化悬空指针或将其设置为空。

如果您不重新初始化它,则循环中对 *pOverlapped 的下一次访问将访问死内存(这可能看起来“有效”),并且下一次尝试删除< /code> 它很可能再次崩溃。如果下一次删除尝试再次发生在HandleAcceptRequest末尾,那么行为可能与您最初描述的完全一样。

Sorry, there's no way to really figure anything out from bits and pieces you provided.

However, in the third piece of code you have this call

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

This call will destroy the *pOverlapped object by calling delete on it. (Remember that at the very end of HandleAcceptRequest you do delete pRequest, where pRequest is the parameter of HandleAcceptRequest).

This will make pOverlapped a dangling pointer that points to dead memory. I don't see any place in your code where you would re-initialize that dangling pointer or set it to null.

If you don't re-initialize it, then the next access to *pOverlapped in the cycle will access dead memory (which might appear to "work") and the next attempt to delete it again will most likely crash. If the next delete attempt is the one at the end of HandleAcceptRequest again, then the behavior will probably be exactly as what you originally described.

泅人 2024-10-31 21:07:45
OVERLAPPED* pOverlapped = nullptr;
..
pServer->m_pCompletionPort->GetCompletionStatus(&dwBytes, &ulKey, &pOverlapped, INFINITE);

好的。看来您删除了错误的指针。您在 HandleAcceptRequest() 中删除的不再是指向 OVERLAPPED 的指针,因为该指针已从 OVERLAPPED* 转换为 ACCEPT_REQUEST*。

GetCompletionStatus() 是你自己的吗?

OVERLAPPED* pOverlapped = nullptr;
..
pServer->m_pCompletionPort->GetCompletionStatus(&dwBytes, &ulKey, &pOverlapped, INFINITE);

Ok. It seems you are deleting the wrong pointer. The one you are deleting inside HandleAcceptRequest() is no longer a pointer to an OVERLAPPED, since the pointer has been casted from OVERLAPPED* to ACCEPT_REQUEST*.

Is GetCompletionStatus() your own?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文