curl多线程crash分析

问题描述

在需要并发请求http时,需要通过多线程使用curl库。curl的handle对象只要保证在一个线程中创建使用和销毁,一般就不会有问题。
但是有一种类型的对象叫做curl_share,通过curl_share_init函数创建。用于给多个curl handle对象提供共享数据,如为了降低请求延时,减少dns查询时间,可以共享同一份dns缓存。
crash堆栈


#0  0x00007fe4339c9387 in raise () from /lib64/libc.so.6
#1  0x00007fe4339caa78 in abort () from /lib64/libc.so.6
#2  0x00007fe433a0bed7 in __libc_message () from /lib64/libc.so.6
#3  0x00007fe433a14299 in _int_free () from /lib64/libc.so.6
#4  0x00007fe434c82b6d in hash_element_dtor () from /lib64/libcurl.so.4
#5  0x00007fe434c8297f in Curl_llist_remove () from /lib64/libcurl.so.4
#6  0x00007fe434c8308a in Curl_hash_clean_with_criterium () from /lib64/libcurl.so.4
#7  0x00007fe434c5ebb7 in Curl_fetch_addr () from /lib64/libcurl.so.4
#8  0x00007fe434c5ed24 in Curl_resolv () from /lib64/libcurl.so.4
#9  0x00007fe434c763c5 in Curl_connect () from /lib64/libcurl.so.4
#10 0x00007fe434c857c3 in multi_runsingle () from /lib64/libcurl.so.4
#11 0x00007fe434c860f9 in curl_multi_perform () from /lib64/libcurl.so.4
#12 0x00007fe434c7e7db in curl_easy_perform () from /lib64/libcurl.so.4

解决方法:
设置加解锁函数才可以加锁保护

static void curl_dns_lock(CURL *h, curl_lock_data data, curl_lock_access access, void*userptr) {
    dns_mutex.lock();
}

static void curl_dns_unlock(CURL *h, curl_lock_data data, curl_lock_access access, void*userptr) {
    dns_mutex.unlock();
}
curl_share_setopt(dns_share_handle, CURLSHOPT_LOCKFUNC, curl_dns_lock);
curl_share_setopt(dns_share_handle, CURLSHOPT_UNLOCKFUNC, curl_dns_unlock);

分析过程分享

通过堆栈发现和dns有关,因为有函数Curl_resolv。
查看curl源码

git clone https://github.com/curl/curl.git
struct Curl_dns_entry *
Curl_fetch_addr(struct Curl_easy *data,
const char *hostname,
int port)
{
    struct Curl_dns_entry *dns = NULL;

    if(data->share)
        Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);

    dns = fetch_addr(data, hostname, port);

    if(dns)
        dns->inuse++; /* we use it! */

    if(data->share)
        Curl_share_unlock(data, CURL_LOCK_DATA_DNS);

    return dns;
}

发现此处获取地址,需要加锁。但是如果加锁了应该不会出crash才对。
//初始化时,是这么写的

dns_share_handle = curl_share_init();  
curl_share_setopt(curl_dns_share_handle, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);

查看share->lockfunc赋值代码,发现是在curl_share_setopt中设置的:

curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...) {
case CURLSHOPT_LOCKFUNC:
    lockfunc = va_arg(param, curl_lock_function);
    share->lockfunc = lockfunc;
    break;

  case CURLSHOPT_UNLOCKFUNC:
    unlockfunc = va_arg(param, curl_unlock_function);
    share->unlockfunc = unlockfunc;
    break;
}

你可能感兴趣的:(curl多线程crash分析)