Segfault with multi-threaded curl request

I have problems with a C ++ program. Basically, I wrote a simple wrapper for http requests, with the ability to make multiple requests at once. Works fine, but when I make httpS requests, it accidentally crashes in multithreaded mode. I use curls and posiki. Backtrace is as follows:

======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x80996)[0x7fea9046d996]
/lib/x86_64-linux-gnu/libc.so.6(+0x82b80)[0x7fea9046fb80]
/lib/x86_64-linux-gnu/libc.so.6(realloc+0xf2)[0x7fea90470ae2]
/lib/x86_64-linux-gnu/libcrypto.so.1.0.0(CRYPTO_realloc+0x49)[0x7fea8f9c6169]
/lib/x86_64-linux-gnu/libcrypto.so.1.0.0(lh_insert+0x101)[0x7fea8fa4bfb1]
/lib/x86_64-linux-gnu/libcrypto.so.1.0.0(+0xe844e)[0x7fea8fa4e44e]
/lib/x86_64-linux-gnu/libcrypto.so.1.0.0(ERR_get_state+0xde)[0x7fea8fa4eeee]
/lib/x86_64-linux-gnu/libcrypto.so.1.0.0(ERR_clear_error+0x15)[0x7fea8fa4f065]
/usr/lib/x86_64-linux-gnu/libcurl.so.4(+0x24e79)[0x7fea90f10e79]
/usr/lib/x86_64-linux-gnu/libcurl.so.4(+0x39ea0)[0x7fea90f25ea0]
/usr/lib/x86_64-linux-gnu/libcurl.so.4(+0xf8fd)[0x7fea90efb8fd]
/usr/lib/x86_64-linux-gnu/libcurl.so.4(+0x219f5)[0x7fea90f0d9f5]
/usr/lib/x86_64-linux-gnu/libcurl.so.4(+0x35538)[0x7fea90f21538]
/usr/lib/x86_64-linux-gnu/libcurl.so.4(curl_multi_perform+0x91)[0x7fea90f21d31]
/usr/lib/x86_64-linux-gnu/libcurl.so.4(curl_easy_perform+0x107)[0x7fea90f19457]
./exbot[0x40273a]
/lib/x86_64-linux-gnu/libpthread.so.0(+0x7f6e)[0x7fea90cd6f6e]
/lib/x86_64-linux-gnu/libc.so.6(clone+0x6d)[0x7fea904e79cd]

Could this be a bug in libcrypto? Can I somehow say curl so as not to use libcrypto? Any alternatives? It only tolerates wenn using httpS requests and works fine even with 10,000 concurrent HTTP requests.

Cheers, Thomas

Just to complete my code:

// simple wrapper for http requests

#ifndef _REQUEST_H_
#define _REQUEST_H_


#include <curl/curl.h>
#include <pthread.h>
#include <string>
#include <iostream>


//////////////////////////////////
// MACROS
//////////////////////////////////
#define ERR(_msg) std::cerr << __FUNCTION__ << ": " << _msg << std::endl


//////////////////////////////////
// REQUEST WRAPPER
//////////////////////////////////
typedef unsigned int uint;
class RequestWrapper
{
private: // non copyable
    RequestWrapper();
    RequestWrapper(const RequestWrapper &that);
    RequestWrapper &operator=(const RequestWrapper &that);

public:
    struct Response
    {
        Response() : msg(""), success(false) {}
        std::string msg;
        bool success;
    };

    static Response simpleGET(std::string url, uint timeout);
    static size_t write(char *content, size_t size, size_t nmemb, void *userp);
};


//////////////////////////////////
// GET
//////////////////////////////////
inline size_t RequestWrapper::write(char *content, size_t size, size_t nmemb, void *userp)
{
    std::string *buf = static_cast<std::string *>(userp);
    size_t realsize = size * nmemb;
    for (uint i = 0; i < realsize; ++i)
    {
        buf->push_back(content[i]);
    }
    return realsize;
}
inline RequestWrapper::Response RequestWrapper::simpleGET(std::string url, uint timeout)
{
    Response resp;
    CURL *curl;
    CURLcode res;
    std::string buf;

    // send request
    buf.clear();
    curl = curl_easy_init();
    if (!curl)
    {
        //ERR("libcurl init failed");
        return resp;
    }
    curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, static_cast<void *>(&buf));
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout);
    res = curl_easy_perform(curl);
    if(res != CURLE_OK)
    {
        //ERR("libcurl request failed, CODE: " << res);
        return resp;
    }
    curl_easy_cleanup(curl);

    // done
    resp.msg = buf;
    resp.success = true;
    return resp;
}


//////////////////////////////////
// MULTITHREADED REQUEST
//////////////////////////////////
class RequestList
{
private:
    std::vector<std::string> _reqs;
    static void *sender(void *payload);
    static pthread_mutex_t _mutex;

public:
    inline void add(std::string request)
    {
        _reqs.push_back(request);
    }

    inline void clear()
    {
        _reqs.clear();
    }

    std::vector<std::string> send(uint timeout) const;

    struct Payload
    {
        std::string url;
        std::vector<std::string> *out;
        uint tout, index;
        Payload(std::string url,
                std::vector<std::string> *out,
                uint tout, uint index) : url(url), out(out), tout(tout), index(index) { }
        Payload() : url(""), out(NULL), tout(0), index(0) { }
    };
};


//////////////////////////////////
// SEND MT REQUEST
//////////////////////////////////
pthread_mutex_t RequestList::_mutex;
void *RequestList::sender(void *payload)
{
    Payload *pl = static_cast<Payload *>(payload);
    RequestWrapper::Response resp = RequestWrapper::simpleGET(pl->url, pl->tout);
    pthread_mutex_lock(&_mutex);
    if (resp.success)
    {
        pl->out->at(pl->index) = resp.msg;
        std::cerr << ".";
    }
    else
    {
        std::cerr << "x";
    }
    pthread_mutex_unlock(&_mutex);
    return NULL;
}
inline std::vector<std::string> RequestList::send(uint timeout) const
{
    std::vector<std::string> resp;
    resp.resize(_reqs.size());
    Payload *payloads = new Payload[_reqs.size()];
    pthread_t *tids = new pthread_t[_reqs.size()];

    // create mutex
    pthread_mutex_init(&_mutex, NULL);

    // prepare payload and create thread
    for (uint i = 0; i < _reqs.size(); ++i)
    {
        payloads[i] = Payload(_reqs[i], &resp, timeout, i);
        pthread_create(&tids[i], NULL, RequestList::sender, static_cast<void *>(&payloads[i]));
    }

    // wait for threads to finish
    for (uint i = 0; i < _reqs.size(); ++i)
    {
        pthread_join(tids[i], NULL);
    }
    std::cerr << std::endl;

    //destroy mutex
    pthread_mutex_destroy(&_mutex);

    delete[] payloads;
    delete[] tids;
    return resp;
}


#endif
+4
source share
1

Libcrypto OpenSSL, , . , POSIX- ( thread-local errno), , :

void locking_function(int mode, int n, const char *file, int line);

CRYPTO_num_locks() n -th mode. . - libcurl , , .

libcurl SSL, , GnuTLS.

+5

Source: https://habr.com/ru/post/1547270/


All Articles