libcurl 中的分段错误,多线程
Posted
技术标签:
【中文标题】libcurl 中的分段错误,多线程【英文标题】:Segmentation fault in libcurl, multithreaded 【发布时间】:2011-03-17 22:03:30 【问题描述】:所以我有一堆工作线程做简单的 curl 类,每个工作线程都有自己的 curl 简单句柄。他们只在随机网站上进行 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 调用它永远不会中断,所以我在想它连接到线程,或者可能是如何返回数据返回结构,但从我在跟踪中看到的看起来就像在 easy_perform() 调用中产生的错误一样,这让我很困惑。 因此,如果有人知道我接下来应该在哪里看,那将是最有帮助的,谢谢。
【问题讨论】:
【参考方案1】: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
已经声称是线程安全的 不需要任何东西。
亚瑟
需要的操作未知。
当使用多个线程时,你应该 将 CURLOPT_NOSIGNAL 选项设置为 1 适用于所有手柄。一切都会或 可能工作正常,除了超时 在 DNS 查找期间不接受 - 你可以通过构建带有 c-ares 支持的 libcurl 来解决这个问题。 c-ares 是一个提供 异步名称解析。一些 平台,libcurl 根本不会 正常运行多线程 除非设置了这个选项。
另外,请注意 CURLOPT_DNS_USE_GLOBAL_CACHE 不是 线程安全。
【讨论】:
是的,我已经阅读了 curl 的那部分内容,并且我的程序遵循了那里的所有指南。但我已经找到了问题,它不是卷曲错误,它只是调试器指向那里。我确实学到了一些关于 curl 的新东西,谢谢。【参考方案2】:如error: longjmp causes uninitialized stack frame 中所述,Debian/Ubuntu 存储库中的最新 libcurl 版本 (>= 7.32.0) 包含一个新的多线程解析器来解决这些问题。 c-ares 支持不是一个好的解决方案:
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=570436#74
“真正的问题是,c-ares 还不能完全替代 gethostby* 功能(例如,它不支持多播 DNS)并且在库存 libcurl 包中启用它可能不是一个好的举措(请注意,这些是词curl 和 c-ares 的上游作者,不是我的)。”-
【讨论】:
以上是关于libcurl 中的分段错误,多线程的主要内容,如果未能解决你的问题,请参考以下文章