MFC的CSocket的一個小Bug?

      今天寫的程序用到了MFC的CSocket類 。

      首先在一個自己的線程中調用這個CSocket類對象的創建函數CSocket::Create(),這個線程用來執行ReSipRocate的協議棧。

      然後當點擊程序窗口的菜單時,程序的主線程(UI線程)調用銷燬函數CSocket::Close()。當程序是Debug版本的時候,會報告一個斷言錯誤 “Debug Assertion Failed. File: sockcore.cpp. Line: 544”。(我用的是VC.net 2003。)

      打開文件看到這個斷言錯誤發生在CSocket的積累CAsyncSocket的處理中。我來回的分析我的CSocket對象的各種操作,確認各個操作均沒有錯誤。好在能單步調試sockcore.cpp文件裏的函數。可以看到斷言的位置爲(標爲紅色字體):

 void PASCAL CAsyncSocket::KillSocket(SOCKET hSocket, CAsyncSocket* pSocket)
{
 ASSERT(CAsyncSocket::LookupHandle(hSocket, FALSE) != NULL);

       _AFX_SOCK_THREAD_STATE* pState = _afxSockThreadState;

       CAsyncSocket::DetachHandle(hSocket, FALSE);
       if (pState->m_hSocketWindow != NULL)
       {
              ::PostMessage(pState->m_hSocketWindow, WM_SOCKET_DEAD,
                 (WPARAM)hSocket, 0L);
              CAsyncSocket::AttachHandle(hSocket, pSocket, TRUE);
        }
}

       於是找到LookupHandle()的定義,如下:

CAsyncSocket* PASCAL CAsyncSocket::LookupHandle(SOCKET hSocket, BOOL bDead)
{
        CAsyncSocket* pSocket;
        _AFX_SOCK_THREAD_STATE* pState = _afxSockThreadState;
        if (!bDead)
        {
               pSocket = (CAsyncSocket*)
               pState->m_pmapSocketHandle->GetValueAt((void*)hSocket);
               if (pSocket != NULL)
                       return pSocket;
         }

         。。。
 }

      看 出來問題出在pState->m_pmapSocketHandle->GetValueAt((void*)hSocket),在根據 SOCKET hSocket查找對應的CAsyncSocket對象指針時失敗了。於是跟蹤m_pmapSocketHandle這個結構的所有操作的地方。在程序運 行的全過程中,只看到將hSocket放入到m_pmapSocketHandle中的操作(pState->m_pmapSocketHandle->SetAt((void*)hSocket, pSocket))。沒有看到從m_pmapSocketHandle中移除hSocket的操作(pState-> m_pmapSocketHandle->RemoveKey((void*)hSocket))。然而爲什麼使用這個hSocket來查找的時候 會失敗呢(pState->m_pmapSocketHandle->GetValueAt((void*)hSocket))?

      開 始分析的時候覺得是不是程序哪裏越界了,導致這個數據結構被破壞了?太可怕了,不願意相信,還是再看看有沒有別的可能。再看看  _AFX_SOCK_THREAD_STATE* pState = _afxSockThreadState這句語句。發現_afxSockThreadState不是一個全局變量,而是一個宏定義。展開來是:

                        #define _afxSockThreadState AfxGetModuleThreadState()


      進一步跟進:

AFX_MODULE_THREAD_STATE* AFXAPI AfxGetModuleThreadState()
{
        return AfxGetModuleState()->m_thread.GetData();
}

      再 往下就發現這個這個pState是線程相關的,不同的線程擁有各自不同的pState。當調用CSocket::Create()創建socket時, SIP協議棧線程把這個socket記錄到自己的pState->m_pmapSocketHandle中。等調用CSocket::Close ()關閉這個socket時,UI線程在關閉前先去自己的pState->m_pmapSocketHandle中查找這個socket。(當然查 不到),所以斷言失敗。

      不知道這是一個Bug還是故意這麼設計的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章