libcurl域名检测超时段错误分析

6 篇文章 0 订阅

堆栈打印

 [sigaction_func:42] signo 11
 [sigaction_func:43] si_signo 11; si_pid 232145656; si_uid 1186409107!
 [sigaction_func:52] SegmentFault!
 [print_backtrace:569] =============================
 [print_backtrace:570] backtrace() start
 [print_backtrace:571] returned 9 addresses
 [print_backtrace:585] 0:./main.exe(print_backtrace+0x20) [0x49882c]
 [print_backtrace:585] 1:./main.exe() [0x4170fc]
 [print_backtrace:585] 2:linux-vdso.so.1(__kernel_rt_sigreturn+0) [0x7fa182c63c]
 [print_backtrace:585] 3:/usr/lib/libcurl.so.4(+0x20e48) [0x7fa17bae48]
 [print_backtrace:585] 4:/usr/lib/libcurl.so.4(+0x21340) [0x7fa17bb340]
 [print_backtrace:585] 5:/usr/lib/libcurl.so.4(curl_mvsnprintf+0x38) [0x7fa17bc448]
 [print_backtrace:585] 6:/usr/lib/libcurl.so.4(+0x12d4c) [0x7fa17acd4c]
 [print_backtrace:585] 7:/usr/lib/libcurl.so.4(+0x968c) [0x7fa17a368c]
 [print_backtrace:585] 8:/lib64/libc.so.6(+0x176cb8) [0x7fa0ed5cb8]
 [print_backtrace:587] backtrace end--------------

测试发现的现象:

  1. 在域名检测超时时,会出现段错误
  2. 在测试程序中,关闭轮询线程(单线程运行),域名检测超时了也没有段错误

根据现象,应该是线程安全问题;

根据堆栈打印,得知,段错误出现在curl_mvsnprintf函数中,在curl代码中查找到# define vsnprintf curl_mvsnprintf

 [print_backtrace:585] 3:/usr/lib/libcurl.so.4(+0x20e48) [0x7fa17bae48]
 [print_backtrace:585] 4:/usr/lib/libcurl.so.4(+0x21340) [0x7fa17bb340]
 [print_backtrace:585] 5:/usr/lib/libcurl.so.4(curl_mvsnprintf+0x38) [0x7fa17bc448]

找到堆栈最后一个,

 [print_backtrace:585] 7:/usr/lib/libcurl.so.4(+0x968c) [0x7fa17a368c]

在libcurl.so.4.4.0.S代码中对应的Curl_resolv_timeout函数的位置

0000000000009610 <Curl_resolv_timeout>:
...
    968c:	b94057a0 	ldr	w0, [x29, #84]
    9690:	340007e0 	cbz	w0, 978c <Curl_resolv_timeout+0x17c>
...

curl-7_50_0 : lib/hostip.c :: Curl_resolv_timeout()

/*
 * Curl_resolv_timeout() is the same as Curl_resolv() but specifies a
 * timeout.  This function might return immediately if we're using asynch
 * resolves. See the return codes.
 *
 * The cache entry we return will get its 'inuse' counter increased when this
 * function is used. You MUST call Curl_resolv_unlock() later (when you're
 * done using this struct) to decrease the counter again.
 *
 * If built with a synchronous resolver and use of signals is not
 * disabled by the application, then a nonzero timeout will cause a
 * timeout after the specified number of milliseconds. Otherwise, timeout
 * is ignored.
 *
 * Return codes:
 *
 * CURLRESOLV_TIMEDOUT(-2) = warning, time too short or previous alarm expired
 * CURLRESOLV_ERROR   (-1) = error, no pointer
 * CURLRESOLV_RESOLVED (0) = OK, pointer provided
 * CURLRESOLV_PENDING  (1) = waiting for response, no pointer
 */

int Curl_resolv_timeout(struct connectdata *conn,
                        const char *hostname,
                        int port,
                        struct Curl_dns_entry **entry,
                        long timeoutms)
{

这个函数里使用了SIGALRM,且这个函数里,先将原有的信号处理设置保存,设置新的SIGALRM信号处理,处理完后,再恢复,使用了sigaction接口,信号处理函数是

#ifdef HAVE_SIGSETJMP
/* Beware this is a global and unique instance. This is used to store the
   return address that we can jump back to from inside a signal handler. This
   is not thread-safe stuff. */
sigjmp_buf curl_jmpenv;
#endif

RETSIGTYPE alarmfunc(int sig)
{
  /* this is for "-ansi -Wall -pedantic" to stop complaining!   (rabe) */
  (void)sig;
  siglongjmp(curl_jmpenv, 1);
  return;
}

curl_jmpenv是全局的!

Curl_resolv_timeout中有个条件是:

  if(data->set.no_signal)
    /* Ignore the timeout when signals are disabled */
    timeout = 0;
  else
    timeout = timeoutms;

  if(!timeout)
    /* USE_ALARM_TIMEOUT defined, but no timeout actually requested */
    return Curl_resolv(conn, hostname, port, entry);

搜索了下set.no_signal得到:

  case CURLOPT_NOSIGNAL:
    /*
     * The application asks not to set any signal() or alarm() handlers,
     * even when using a timeout.
     */
    data->set.no_signal = (0 != va_arg(param, long)) ? TRUE : FALSE;
    break;

在测试代码中,对接口设置

curl_easy_setopt(webProxy->hCurl, CURLOPT_NOSIGNAL, 1L); 

进行测试,域名检测超时后,没有发现段错误

费劲半天,早知道百度一下就解决了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值