libcurl中的分段错误,多线程

时间:2010-07-19 13:20:46

标签: c curl segmentation-fault pthreads

所以我有一堆工作线程做简单的curl类,每个工作线程都有自己的curl easy handle。他们只在随机网站上进行HEAD查找。此外,还存在锁定函数以启用多线程SSL,如文档here所示。一切正常,除了2个网页ilsole24ore.com(见例下)和ninemsn.com.au/,它们有时会产生seg故障,如此处所示的跟踪输出所示

 #0  *__GI___libc_res_nquery (statp=0xb4d12df4, name=0x849e9bd "ilsole24ore.com", class=1, type=1, answer=0xb4d0ca10 "", anslen=1024, answerp=0xb4d0d234,
        answerp2=0x0, nanswerp2=0x0, resplen2=0x0) at res_query.c:182
    #1  0x00434e8b in __libc_res_nquerydomain (statp=0xb4d12df4, name=0xb4d0ca10 "", domain=0x0, class=1, type=1, answer=0xb4d0ca10 "", anslen=1024,
        answerp=0xb4d0d234, answerp2=0x0, nanswerp2=0x0, resplen2=0x0) at res_query.c:576
    #2  0x004352b5 in *__GI___libc_res_nsearch (statp=0xb4d12df4, name=0x849e9bd "ilsole24ore.com", class=1, type=1, answer=0xb4d0ca10 "", anslen=1024,
        answerp=0xb4d0d234, answerp2=0x0, nanswerp2=0x0, resplen2=0x0) at res_query.c:377
    #3  0x009c0bd6 in *__GI__nss_dns_gethostbyname3_r (name=0x849e9bd "ilsole24ore.com", af=2, result=0xb4d0d5fc, buffer=0xb4d0d300 "\177", buflen=512,
        errnop=0xb4d12b30, h_errnop=0xb4d0d614, ttlp=0x0, canonp=0x0) at nss_dns/dns-host.c:197
    #4  0x009c0f2b in _nss_dns_gethostbyname2_r (name=0x849e9bd "ilsole24ore.com", af=2, result=0xb4d0d5fc, buffer=0xb4d0d300 "\177", buflen=512,
        errnop=0xb4d12b30, h_errnop=0xb4d0d614) at nss_dns/dns-host.c:251
    #5  0x0079eacd in __gethostbyname2_r (name=0x849e9bd "ilsole24ore.com", af=2, resbuf=0xb4d0d5fc, buffer=0xb4d0d300 "\177", buflen=512, result=0xb4d0d618,
        h_errnop=0xb4d0d614) at ../nss/getXXbyYY_r.c:253
    #6  0x00760010 in gaih_inet (name=<value optimized out>, service=<value optimized out>, req=0xb4d0f83c, pai=0xb4d0d764, naddrs=0xb4d0d754)
        at ../sysdeps/posix/getaddrinfo.c:531
    #7  0x00761a65 in *__GI_getaddrinfo (name=0x849e9bd "ilsole24ore.com", service=0x0, hints=0xb4d0f83c, pai=0xb4d0f860) at ../sysdeps/posix/getaddrinfo.c:2160
    #8  0x00917f9a in ?? () from /usr/lib/libkrb5support.so.0
    #9  0x003b2f45 in krb5_sname_to_principal () from /usr/lib/libkrb5.so.3
    #10 0x0028a278 in ?? () from /usr/lib/libgssapi_krb5.so.2
    #11 0x0027eff2 in ?? () from /usr/lib/libgssapi_krb5.so.2
    #12 0x0027fb00 in gss_init_sec_context () from /usr/lib/libgssapi_krb5.so.2
    #13 0x00d8770e in ?? () from /usr/lib/libcurl.so.4
    #14 0x00d62c27 in ?? () from /usr/lib/libcurl.so.4
    #15 0x00d7e25b in ?? () from /usr/lib/libcurl.so.4
    #16 0x00d7e597 in ?? () from /usr/lib/libcurl.so.4
    #17 0x00d7f133 in curl_easy_perform () from /usr/lib/libcurl.so.4

我的功能看起来像这样

int do_http_check(taskinfo *info,standardResult *data)
{
    standardResultInit(data);

    char errorBuffer[CURL_ERROR_SIZE];

    CURL *curl;
    CURLcode result;

    curl = curl_easy_init();

    if(curl)
    {
        //required options first
        curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorBuffer);
        curl_easy_setopt(curl, CURLOPT_URL, info->address.c_str());
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writer);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data->body);
        curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, writer);
        curl_easy_setopt(curl, CURLOPT_WRITEHEADER, &data->head);
        curl_easy_setopt(curl, CURLOPT_DNS_USE_GLOBAL_CACHE,0);
        curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 30 );
        curl_easy_setopt(curl, CURLOPT_NOSIGNAL,1);
        curl_easy_setopt(curl, CURLOPT_NOBODY,1);
        curl_easy_setopt(curl, CURLOPT_TIMEOUT ,240);

        //optional options
        if(info->options.follow)
        {
            curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
            curl_easy_setopt(curl, CURLOPT_MAXREDIRS, info->options.redirects);
        }

        result = curl_easy_perform(curl);

        if (result == CURLE_OK)
        {
            data->success = true;
            curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE,&data->httpMsg);
            curl_easy_getinfo(curl,CURLINFO_REDIRECT_COUNT,&data->numRedirects);
            data->msg = "OK";
        }
        else
        {
            ... handle error
        }


    return 1;
}

现在,当我在没有任何线程的情况下调用函数时,只是从main调用它永远不会中断,所以我认为它连接到线程,或者可能是如何返回数据返回结构,但是从我在trace中看到它看起来就像在easy_perform()调用中生成错误一样,它让我很困惑。 因此,如果有人知道我应该在哪里看,那将是最有帮助的,谢谢。

2 个答案:

答案 0 :(得分:13)

libcurl to Multi-Threading专用了整个部分。

  

第一个基本规则是你必须   从不共享libcurl句柄(是的   容易或多或其他)之间   多线程。只使用一个手柄   在一个线程中一次。

     

libcurl完全是线程安全的   除了两个问题:信号和   SSL / TLS处理程序。信号用于   超时名称解析(在DNS期间)   查找) - 在没有c-ares的情况下构建   支持而不是Windows。

     

如果您正在访问HTTPS或FTPS   您可以使用多线程方式访问URL   然后当然使用   底层SSL库多线程   那些图书馆可能有自己的   关于这个问题的要求。基本上,   你需要提供一两个   功能,使其能够运作   正常。有关所有详细信息,请参阅:

     

OpenSSL的

     

http://www.openssl.org/docs/crypto/threads.html#DESCRIPTION

     

的GnuTLS

     

http://www.gnu.org/software/gnutls/manual/html_node/Multi_002dthreaded-applications.html

     

NSS

     

声称已经是线程安全的   没有任何要求。

     

yassl

     

所需行动未知。

     

使用多个线程时应该   将CURLOPT_NOSIGNAL选项设置为1   适用于所有手柄。一切都会或   可能会工作正常,除了超时   在DNS查找期间不受尊重    - 你可以通过构建具有c-ares支持的libcurl来解决这个问题。   c-ares是一个提供的库   异步名称解析。一些   平台,libcurl根本不会   功能正常多线程   除非设置此选项。

     

另外,请注意   CURLOPT_DNS_USE_GLOBAL_CACHE不是   线程安全的。

答案 1 :(得分:0)

error: longjmp causes uninitialized stack frame中所述,Debian / Ubuntu存储库中的最新libcurl版本(&gt; = 7.32.0)包含一个新的多线程解析器来解决这些问题。 c-ares支持不是一个好的解决方案:

https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=570436#74

&#34;真正的问题是c-ares还不是gethostby *函数的完全替代品(例如它不支持多播DNS)并且在库存libcurl包中启用它可能不是一个好的举动(请注意这些是curl和c-ares的上游作者的话,而不是我的。&#34; -