LINUX.ORG.RU

В libcurl утечка памяти чтоли

 , ,


0

3

Сделал пачку потоков в которых забирал файлы по https
Заметил что сильно отъедает память Для проверки сделал тестовый кусок кода, поднял апач и в цикле забирал один и тот же файл:

#include <curl/curl.h>
#include <thread>

size_t writefunc(void* ptr, size_t size, size_t nmemb, std::string* userdata) {

    return size*nmemb;
}

void thread_test() {

    const char* url = "https://КАКОЙ-ТО УРЛ";

    CURL* curl;
    CURLcode res;

    while(true) {

    curl = curl_easy_init();

    curl_easy_setopt(curl, CURLOPT_URL, url);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); // Не будем проверять сертификаты
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); // Не будем проверять сертификаты

    //чтобы не валило в stdout
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writefunc);
//	curl_easy_setopt(curl, CURLOPT_WRITEDATA, &write_data);


//	curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);

    res = curl_easy_perform(curl);

    //Если что-то пошло не так...
    if(res != CURLE_OK) {

        curl_easy_strerror(res);
    } else {

    //Все OK

    }

    curl_easy_cleanup(curl);

    }


}

main() {

    curl_global_init(CURL_GLOBAL_ALL);

    int thread_num = 100;

    //Запускаем потоки
    std::thread threads[thread_num];
    for(int i = 0 ; i < thread_num ; i++) {

    threads[i] = std::thread(thread_test);
    }

    for(int i = 0 ; i < thread_num ; i++) {

    threads[i].join();
    }

}


собираем
g++ -std=c++11 curl-test-0.cpp -lcurl -lpthread -o curl-test-0
ldd:
	linux-vdso.so.1 (0x00007ffcf8d6c000)
	libcurl-nss.so.4 => /usr/lib/x86_64-linux-gnu/libcurl-nss.so.4 (0x00007f679df56000)
	libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f679dd39000)
	libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f679d9b7000)
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f679d6b3000)
	libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f679d49c000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f679d0fd000)
	libnghttp2.so.14 => /usr/lib/x86_64-linux-gnu/libnghttp2.so.14 (0x00007f679ced7000)
	libidn2.so.0 => /usr/lib/x86_64-linux-gnu/libidn2.so.0 (0x00007f679ccb5000)
	librtmp.so.1 => /usr/lib/x86_64-linux-gnu/librtmp.so.1 (0x00007f679ca98000)
	libssh2.so.1 => /usr/lib/x86_64-linux-gnu/libssh2.so.1 (0x00007f679c86c000)
	libpsl.so.5 => /usr/lib/x86_64-linux-gnu/libpsl.so.5 (0x00007f679c65e000)
	libnss3.so => /usr/lib/x86_64-linux-gnu/libnss3.so (0x00007f679c314000)
	libnssutil3.so => /usr/lib/x86_64-linux-gnu/libnssutil3.so (0x00007f679c0e6000)
	libsmime3.so => /usr/lib/x86_64-linux-gnu/libsmime3.so (0x00007f679beb9000)
	libssl3.so => /usr/lib/x86_64-linux-gnu/libssl3.so (0x00007f679bc61000)
	libplds4.so => /usr/lib/x86_64-linux-gnu/libplds4.so (0x00007f679ba5d000)
	libplc4.so => /usr/lib/x86_64-linux-gnu/libplc4.so (0x00007f679b858000)
	libnspr4.so => /usr/lib/x86_64-linux-gnu/libnspr4.so (0x00007f679b618000)
	libgssapi_krb5.so.2 => /usr/lib/x86_64-linux-gnu/libgssapi_krb5.so.2 (0x00007f679b3cd000)
	libkrb5.so.3 => /usr/lib/x86_64-linux-gnu/libkrb5.so.3 (0x00007f679b0f3000)
	libk5crypto.so.3 => /usr/lib/x86_64-linux-gnu/libk5crypto.so.3 (0x00007f679aec0000)
	libcom_err.so.2 => /lib/x86_64-linux-gnu/libcom_err.so.2 (0x00007f679acbc000)
	liblber-2.4.so.2 => /usr/lib/x86_64-linux-gnu/liblber-2.4.so.2 (0x00007f679aaad000)
	libldap_r-2.4.so.2 => /usr/lib/x86_64-linux-gnu/libldap_r-2.4.so.2 (0x00007f679a85c000)
	libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f679a642000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f679e3dc000)
	libunistring.so.0 => /usr/lib/x86_64-linux-gnu/libunistring.so.0 (0x00007f679a32b000)
	libgnutls.so.30 => /usr/lib/x86_64-linux-gnu/libgnutls.so.30 (0x00007f6799f92000)
	libhogweed.so.4 => /usr/lib/x86_64-linux-gnu/libhogweed.so.4 (0x00007f6799d5d000)
	libnettle.so.6 => /usr/lib/x86_64-linux-gnu/libnettle.so.6 (0x00007f6799b26000)
	libgmp.so.10 => /usr/lib/x86_64-linux-gnu/libgmp.so.10 (0x00007f67998a3000)
	libgcrypt.so.20 => /lib/x86_64-linux-gnu/libgcrypt.so.20 (0x00007f6799593000)
	libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f679938f000)
	librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f6799187000)
	libkrb5support.so.0 => /usr/lib/x86_64-linux-gnu/libkrb5support.so.0 (0x00007f6798f7b000)
	libkeyutils.so.1 => /lib/x86_64-linux-gnu/libkeyutils.so.1 (0x00007f6798d77000)
	libresolv.so.2 => /lib/x86_64-linux-gnu/libresolv.so.2 (0x00007f6798b60000)
	libsasl2.so.2 => /usr/lib/x86_64-linux-gnu/libsasl2.so.2 (0x00007f6798945000)
	libp11-kit.so.0 => /usr/lib/x86_64-linux-gnu/libp11-kit.so.0 (0x00007f67986e0000)
	libidn.so.11 => /lib/x86_64-linux-gnu/libidn.so.11 (0x00007f67984ac000)
	libtasn1.so.6 => /usr/lib/x86_64-linux-gnu/libtasn1.so.6 (0x00007f6798299000)
	libgpg-error.so.0 => /lib/x86_64-linux-gnu/libgpg-error.so.0 (0x00007f6798085000)
	libffi.so.6 => /usr/lib/x86_64-linux-gnu/libffi.so.6 (0x00007f6797e7c000)

Вскоре после запуска наблюдаем увеличение отъедаемой памяти. На гитхабе были какие-то разговоры про подобное, но решение не засветили. Специально использовал NSS потомучто на офсайте curl сказано что он потокобезопасный, а OpenSSL не всех версий. Проблема наблюдается только при работе по HTTPS.
Это на стретче 64х,

curl 7.52.1 (x86_64-pc-linux-gnu) libcurl/7.52.1 OpenSSL/1.0.2q zlib/1.2.8 libidn2/0.16 libpsl/0.17.0 (+libidn2/0.16) libssh2/1.7.0 nghttp2/1.18.1 librtmp/2.3
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp scp sftp smb smbs smtp smtps telnet tftp 
Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz TLS-SRP HTTP2 UnixSockets HTTPS-proxy PSL

Как быть?


Специально использовал NSS потомучто на офсайте curl сказано что он потокобезопасный, а OpenSSL не всех версий.

А как именно ты «использовал NSS»? У тебя же сам curl говорит, что он собран с OpenSSL 1.0.2q.

mironov_ivan ★★★★★ ()
Ответ на: комментарий от ocr

Так как у тебя не совсем «настоящая» утечка, так как curl_global_cleanup всё очищает, то видимо надо смотреть куда-то в сторону http://valgrind.org/docs/manual/ms-manual.html.

Кстати, видел вот это: https://github.com/curl/curl/issues/1086?

mironov_ivan ★★★★★ ()
Ответ на: комментарий от mironov_ivan

Мне кажется он чёт некорректно использует. У меня с openssl нормально работало, кода там побольше было правда. А в примерах на сайте есть и для gnutls.

anonymous ()
Ответ на: комментарий от ocr

мне вот интересно как вы в дальнейшем собираетесь работать в той компании в которую вас собеседуют или наняли, если в трех строчках разобраться не в силах ?

anonymous ()
Ответ на: комментарий от anonymous

я не знал что придется пилить всякие костыли и в таких дебрях копаться. скажут досвидания, «отнесусь с пониманием», я знаю что как спец сейчас я гавно. Хотябы буду знать что приложил все усилия что мог

ocr ()
Ответ на: комментарий от anonymous

уже увидел и делаю это
интересная ситуация со стретчем и dev-пакетами для curl: есть libcurl4-openssl-dev, но он для openssl 1.0.2, а тот что тред-сэйф версии 1.1 для него нет dev-пакета для curl и придется либо собирать с ним curl руками и делать LD_PRELOAD, либо делать блокировки как по ссылке

ocr ()

Похоже, буду оригинален, и скажу следующее:

valgrind даёт много false positives, особенно в приложения использующих кондиционные переменные.

Вместо этого можно попробовать штатные механизмы компилятора(curl придётся собрать из исходников и может ещё что-то):

man gcc | grep asan -C 10

Можно ещё подумать как-то так. Хотя я бы попробовал сначала руками собрать.

pon4ik ★★★★★ ()
Ответ на: комментарий от anonymous

спасибо, анон
для OpenSSL версий старше 1.1 понапилил блокировок как в примере и все перестало течь

Только с NSS непонятно почему протекает, на офсайте сказано что тредсейф

ocr ()