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:56:25 -0800

Bugs item #1833734, was opened at 2007-11-17 19:31
Message generated for change (Comment added) made by bagder
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: Daniel Stenberg (bagder)
Date: 2007-11-18 16:56

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

Well, I afraid I don't want to see (parts of) your source code. I want a
source code example that repeats your problem, and I want it as a
stand-alone sample that I can compile and run and see the problem appear!

If not, I at least want a lot more details on exactly what call you do
that crashes and what the contents of the local variables are at that
moment etc.

Is the crash happening every time? Did you try using a "memory guard" tool
or similar to track memory abuse/failures? Have you tried this code on any
other platform, host or compiler and did it behave the same way then?

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

Comment By: Guodong Ding (gdding)
Date: 2007-11-18 16: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 10: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