美文网首页
curl多线程crash分析

curl多线程crash分析

作者: 我是榜样 | 来源:发表于2022-09-21 21:06 被阅读0次

    问题描述

    在需要并发请求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分析

          本文链接:https://www.haomeiwen.com/subject/aejiortx.html