cURL
Haxx ad
libcurl

curl's project page on SourceForge.net

Sponsors:
Haxx

cURL > Mailing List > Monthly Index > Single Mail

curl-tracker mailing list Archives

[ curl-Bugs-1833734 ] Curl_llist_insert_next crashes occasionally

From: SourceForge.net <noreply_at_sourceforge.net>
Date: Sun, 18 Nov 2007 07:31:14 -0800

Bugs item #1833734, was opened at 2007-11-17 18:31
Message generated for change (Comment added) made by gdding
You can respond by visiting:
https://sourceforge.net/tracker/?func=detail&atid=100976&aid=1833734&group_id=976

Please note that this message will contain a full copy of the comment thread,
including the initial issue submission, for this request,
not just the latest update.
Category: libcurl
Group: crash
Status: Open
Resolution: None
Priority: 7
Private: No
Submitted By: Guodong Ding (gdding)
Assigned to: Daniel Stenberg (bagder)
Summary: Curl_llist_insert_next crashes occasionally

Initial Comment:
libcurl version: 7.17.1
Platform: winxp 32-bit + VS.NET2003

Sometimes the function Curl_llist_insert_next() crashes, for the value of parameter 'e' is zero when list->size > 0. See the following code line:
ne->next = e->next;

----------------------------------------------------------------------

>Comment By: Guodong Ding (gdding)
Date: 2007-11-18 15:31

Message:
Logged In: YES
user_id=1939640
Originator: YES

I used the multi interface. The following is the focus part of my source
code. The multi interfaces are called and used mainly in the GatherCore()
function.

/*************************************************/
unsigned int CPageGather::m_nGlobalInitCount = 0;

#ifdef WIN32
void CPageGather::GatherCoreThread(void *p)
{
        CPageGather *pGather = (CPageGather*)p;
        if (pGather != NULL)
        {
                pGather->GatherCore();
        }
}
#else
void* CPageGather::GatherCoreThread(void *p)
{
        CPageGather *pGather = (CPageGather*)p;
        if (pGather != NULL)
        {
                pGather->GatherCore();
        }
        return NULL;
}
#endif

size_t CPageGather::WriteDataCallback(void *ptr, size_t size, size_t
nmemb, void *data)
{
        TEasyCURLInfo* pEasyCURLInfo = (TEasyCURLInfo*)data;
        assert(pEasyCURLInfo != NULL);
        unsigned int nCURLID = pEasyCURLInfo->nCURLID;
        CGatherMemoryMan* pMemoryMan = pEasyCURLInfo->pMemoryMan;
        assert(pMemoryMan != NULL);
        uint32_t nWriteSize = pMemoryMan->PutData(nCURLID, (char*)ptr,
size*nmemb);
        return nWriteSize;
}

CPageGather::CPageGather()
{
        m_pGatherStateMan = NULL;
        m_pGatherRequestMan = NULL;
        m_pGatherMemoryMan = NULL;
        m_pGatherResultMan = NULL;
        m_pMultiCURL = NULL;
        m_pEasyCURLInfoArray = NULL;
    m_nReadRequestCount = 0;
        m_nOutputResultCount = 0;

        if(m_nGlobalInitCount == 0)
        {
                if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK)
                {
                        printf("curl_global_init() failed\n");
                        _exit(-1);
                }
        }
        m_nGlobalInitCount++;
}

CPageGather::~CPageGather()
{
        Exit();

        m_nGlobalInitCount--;
        if(m_nGlobalInitCount == 0)
                curl_global_cleanup();
}

void CPageGather::Exit()
{
        if (m_pGatherMemoryMan != NULL)
        {
                delete m_pGatherMemoryMan;
                m_pGatherMemoryMan = NULL;
        }
        if (m_pGatherStateMan != NULL)
        {
                delete m_pGatherStateMan;
                m_pGatherStateMan = NULL;
        }
        if (m_pGatherResultMan != NULL)
        {
                delete m_pGatherResultMan;
                m_pGatherResultMan = NULL;
        }
        if (m_pGatherRequestMan != NULL)
        {
                delete m_pGatherRequestMan;
                m_pGatherRequestMan = NULL;
        }
        
        if (m_pEasyCURLInfoArray != NULL)
        {
                for(uint32_t i = 0; i < m_nSocketNum; i++)
                {
                        curl_easy_cleanup(m_pEasyCURLInfoArray[i].pEasyCURL);
                }
                delete[] m_pEasyCURLInfoArray;
                m_pEasyCURLInfoArray = NULL;
        }
        while(!m_qFreeEasyCURLID.empty())
                m_qFreeEasyCURLID.pop();

        if (m_pMultiCURL != NULL)
        {
                curl_multi_cleanup(m_pMultiCURL);
                m_pMultiCURL = NULL;
        }
}

bool CPageGather::Init(uint32_t nSocketNum,
                                           bool bRemoveHeader,
                                           uint32_t nMemBlocks,
                                           uint32_t nBlockSize)
{
        //some initializations here...

        //init a multi curl: m_pMultiCURL
        m_pMultiCURL = curl_multi_init();
        if(m_pMultiCURL == NULL)
        {
                delete m_pGatherMemoryMan;
                m_pGatherMemoryMan = NULL;
                return false;
        }

        //init m_pEasyCURLArray, m_qFreeEasyCURLID
        m_pEasyCURLInfoArray = new TEasyCURLInfo[m_nSocketNum];
        assert(m_pEasyCURLInfoArray != NULL);
        for (uint32_t i=0; i<m_nSocketNum; i++)
        {
                //init an easy curl
                CURL* pEasyCURL = curl_easy_init();
                if (pEasyCURL == NULL)
                {
                        printf("curl_easy_init() failed\n");
                        return false;
                }

                //set the ID for the easy curl
                uint32_t nCURLID = i;

                //set values of m_pEasyCURLArray[i]
                m_pEasyCURLInfoArray[i].nCURLID = nCURLID;
                m_pEasyCURLInfoArray[i].pEasyCURL = pEasyCURL;
                m_pEasyCURLInfoArray[i].pMemoryMan = m_pGatherMemoryMan;

                //add the easy curl into the free curl queue
                m_qFreeEasyCURLID.push(nCURLID);

                //set options for the easy curl
                CURLcode rc = CURLE_OK;
                if(!bRemoveHeader)
                {
                        rc = curl_easy_setopt(pEasyCURL, CURLOPT_HEADER, 1);
                        assert(rc == CURLE_OK);
                }
                rc = curl_easy_setopt(pEasyCURL, CURLOPT_AUTOREFERER, 1);
                rc = curl_easy_setopt(pEasyCURL, CURLOPT_FOLLOWLOCATION, 1);
                rc = curl_easy_setopt(pEasyCURL, CURLOPT_MAXREDIRS, 10);
                rc = curl_easy_setopt(pEasyCURL, CURLOPT_WRITEDATA,
(void*)&m_pEasyCURLInfoArray[i]);
                rc = curl_easy_setopt(pEasyCURL, CURLOPT_WRITEFUNCTION,
WriteDataCallback);

#ifdef HAVE_LIBZ
                rc = curl_easy_setopt(pEasyCURL, CURLOPT_ENCODING, "gzip, deflate");
#endif
        }
        
        return true;
}

bool CPageGather::Start(const CPageRequest *pstPageReq, uint32_t nCount)
{
        m_pGatherRequestMan->AddRequests(pstPageReq,nCount);
        m_pGatherStateMan->SetGatherState(STATE_START);

        DEFINE_THREAD(t);
        if (FAILED_THREAD(BEGIN_THREAD(t, GatherCoreThread, (void*)this)))
        {
                m_pGatherRequestMan->Clear();
                m_pGatherStateMan->SetGatherState(STATE_NOT_START);
                return false;
        }

        return true;
}

void CPageGather::Stop()
{
        TGatherState iState = m_pGatherStateMan->GetGatherState();
        assert(iState != STATE_USER_SEND_STOP);
        if (iState == STATE_ALREADY_STOP)
        {
                return;
        }
        while (!m_pGatherStateMan->IsAlreadyStop())
        {
                m_pGatherStateMan->SetGatherState(STATE_USER_SEND_STOP);
                MY_SLEEP(10);
        }
}

int CPageGather::AddRequests(const CPageRequest *pstPageReq, uint32_t
nCount)
{
        assert(m_pGatherRequestMan != NULL);
        return m_pGatherRequestMan->AddRequests(pstPageReq,nCount);
}

GATHER_RESULT* CPageGather::FetchGatherResult(void)
{
        assert(m_pGatherResultMan != NULL);
        return m_pGatherResultMan->FetchGatherResult();
}

void CPageGather::DestroyResult(GATHER_RESULT* pGatherResult)

{
        assert(m_pGatherResultMan != NULL);
        m_pGatherResultMan->DeleteGatherResult(pGatherResult);

}

void CPageGather::GatherCore(void)
{
        DispatchGatherRequests();

        int nStillRunnings = 0;
        while(CURLM_CALL_MULTI_PERFORM ==
                curl_multi_perform(m_pMultiCURL, &nStillRunnings));

        while(!m_pGatherStateMan->IsUserStop())
        {
                nStillRunnings = FdsetSelect();
                ProcessFinishedReqs();
                DispatchGatherRequests();

                _sleep(10);
        }

        m_pGatherStateMan->SetGatherState(STATE_ALREADY_STOP);
}

void CPageGather::DispatchGatherRequests(void)
{
        while(!m_qFreeEasyCURLID.empty())
        {
                //fetch a request, if no requests availabe, return
                const CPageRequest* pRequest = m_pGatherRequestMan->FetchRequest();
                if(pRequest == NULL) return;

                //fetch a free easy curl from the queue
                unsigned int nCURLID = m_qFreeEasyCURLID.front();
                m_qFreeEasyCURLID.pop();

                //create private info passed to the easy curl
                TRequestInfo *pRequestInfo = new TRequestInfo;
                assert(pRequestInfo != NULL);
                pRequestInfo->nCURLID = nCURLID;
                pRequestInfo->pRequest = pRequest;
                
                //set options for the easy curl
                CURL* pEasyCURL = m_pEasyCURLInfoArray[nCURLID].pEasyCURL;
                assert(pEasyCURL != NULL);
                CURLcode rc = CURLE_OK;
                rc = curl_easy_setopt(pEasyCURL, CURLOPT_URL,
pRequest->m_sUrl.c_str());
                assert(rc == CURLE_OK);
                rc = curl_easy_setopt(pEasyCURL, CURLOPT_PRIVATE, (void*)pRequestInfo);
                assert(rc == CURLE_OK);

                //add the easy curl to the multi curl
                CURLMcode mc = CURLM_OK;
                mc = curl_multi_add_handle(m_pMultiCURL, pEasyCURL);
                assert(mc == CURLM_OK);

                //increace the request count read
                m_nReadRequestCount++;
        }
}

int CPageGather::FdsetSelect(void)
{
        assert(m_pMultiCURL != NULL);
        int nStillRunnings = -1;

        struct timeval tTimeout;
        tTimeout.tv_sec = 0;
        tTimeout.tv_usec = 20;

        fd_set fdread;
        fd_set fdwrite;
        fd_set fdexcep;

        FD_ZERO(&fdread);
        FD_ZERO(&fdwrite);
        FD_ZERO(&fdexcep);

        //fdset & select
        int maxfd = 0;
        CURLMcode nRetCode = curl_multi_fdset(m_pMultiCURL, &fdread, &fdwrite,
&fdexcep, &maxfd);
        assert(nRetCode == CURLE_OK);
        if(maxfd > -1)
        {
                int rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &tTimeout);
                switch(rc)
                {
                case -1:
                        //select error
                        fprintf(stderr, "select() returns error, this is badness\n");
                        break;
                case 0:
                        //timeout
                        break;
                default:
                        //readable/writable sockets
                        while(CURLM_CALL_MULTI_PERFORM ==
                                curl_multi_perform(m_pMultiCURL, &nStillRunnings));
                        break;
                }
        }
        return nStillRunnings;
}

void CPageGather::ProcessFinishedReqs(void)
{
        CURLMsg *pCURLMsg = NULL;
        assert(m_pMultiCURL != NULL);
        int nLeftMsgs = 0;
        while ((pCURLMsg = curl_multi_info_read(m_pMultiCURL, &nLeftMsgs)))
        {
                if (pCURLMsg->msg == CURLMSG_DONE)
                {
                        CURLcode nRetCode = pCURLMsg->data.result;
                        CURL *pEasyCURL = pCURLMsg->easy_handle;
                        assert(pEasyCURL != NULL);

                        //get TRequestInfo*
                        TRequestInfo* pRequestInfo = NULL;
                        curl_easy_getinfo(pEasyCURL, CURLINFO_PRIVATE, (char*)&pRequestInfo);
                        assert(pRequestInfo != NULL);
                        const CPageRequest* pRequest = pRequestInfo->pRequest;
                        unsigned int nCURLID = pRequestInfo->nCURLID;
                        delete pRequestInfo;
                        pRequestInfo = NULL;

                        CPageRecord* pResult = new CPageRecord();
                        assert(pResult != NULL);
                        pResult->m_pRequest = pRequest;
                        pResult->m_nTimeStamp = time(NULL);
                        pResult->m_nRetCode = nRetCode;
                        pResult->m_sRetMsg = curl_easy_strerror(nRetCode);
                        if(nRetCode == CURLE_OK)
                        {
                                char* sContentType = NULL;
                                CResponseInfo *pInfo = new CResponseInfo();
                                assert(pInfo != NULL);
                                CURLcode rc = CURLE_OK;
                                rc = curl_easy_getinfo(pEasyCURL, CURLINFO_RESPONSE_CODE,
&pInfo->m_nHttpCode);
                                assert(rc == CURLE_OK);
                                rc = curl_easy_getinfo(pEasyCURL, CURLINFO_TOTAL_TIME,
&pInfo->m_dbTransferSecs);
                                assert(rc == CURLE_OK);
                                rc = curl_easy_getinfo(pEasyCURL, CURLINFO_FILETIME,
&pInfo->m_nFileTime);
                                assert(rc == CURLE_OK);
                                rc = curl_easy_getinfo(pEasyCURL, CURLINFO_CONTENT_TYPE,
&sContentType);
                                assert(rc == CURLE_OK);
                                pInfo->m_sContentType = (sContentType!=NULL?sContentType:"");
                                char* pcURL = NULL;
                                rc = curl_easy_getinfo(pEasyCURL, CURLINFO_EFFECTIVE_URL, &pcURL);
                                assert(rc == CURLE_OK);
                                pInfo->m_sEffectiveURL = pcURL;
                                pResult->m_pResponseInfo = pInfo;

                                assert(m_pGatherMemoryMan != NULL);
                                char* pcData = NULL;
                                uint32_t nDataLen = 0;
                                if(m_pGatherMemoryMan->GetData(nCURLID, pcData, nDataLen))
                                {
                                        pResult->m_pcData = pcData;
                                        pResult->m_nDataLength = nDataLen;
                                }
                        }
                        m_pGatherResultMan->AddGatherResult(pResult);
                        m_nOutputResultCount++;

                        m_pGatherMemoryMan->FreeData(nCURLID);

                        CURLMcode mc = CURLM_OK;
                        mc = curl_multi_remove_handle(m_pMultiCURL, pEasyCURL);
                        assert(mc == CURLM_OK);
                        m_qFreeEasyCURLID.push(nCURLID);

                }

        }
}

----------------------------------------------------------------------

Comment By: Daniel Stenberg (bagder)
Date: 2007-11-18 09:59

Message:
Logged In: YES
user_id=1110
Originator: NO

Can you please tell us how to repeat this problem? Is there a recipe we
can follow? Is there a source code example you use to get this problem?

That code hasn't been modified in a long time and thus is used like that
by millions of people with no problems, why I rather think the error is in
your code...

----------------------------------------------------------------------

You can respond by visiting:
https://sourceforge.net/tracker/?func=detail&atid=100976&aid=1833734&group_id=976
Received on 2007-11-18

These mail archives are generated by hypermail.

donate! Page updated November 12, 2010.
web site info

File upload with ASP.NET