2014-05-14 2 views
0

Я написал простую обертку для завивки, чтобы получить доступ к содержимому http, https. Если я буду запускать свои тестовые файлы с valgrind, я могу видеть некоторые еще доступные области. Да, я знаю, что они не так злы, как потерянные ссылки или определенно проиграли. Но я хочу, чтобы мой проект был чистым.Как использовать curl + ssl без бедствия memleak

Если отключить SSL с помощью curl_global_init(CURL_GLOBAL_NOTHING), никаких обнаруженных memleaks не обнаружено. Но тогда также нет поддержки https. Итак, я полагаю, что это проблема libcrypt, libssl? Что я могу сделать для инициализации и очистки корректного вызова https без уведомления valgrind?

[email protected]:rcc$ valgrind --leak-check=full --show-reachable=yes ./tests/testsuite 
==7171== Memcheck, a memory error detector 
==7171== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al. 
==7171== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info 
==7171== Command: ./tests/testsuite 
==7171== 
==7171== Conditional jump or move depends on uninitialised value(s) 
==7171== at 0x703784B: ASN1_STRING_set (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0) 
==7171== by 0x702552C: ASN1_mbstring_ncopy (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0) 
==7171== by 0x7025753: ASN1_mbstring_copy (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0) 
==7171== by 0x7026614: ASN1_STRING_to_UTF8 (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0) 
==7171== by 0x7027A42: ??? (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0) 
==7171== by 0x7027FA6: ??? (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0) 
==7171== by 0x702E4E2: ASN1_item_ex_d2i (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0) 
==7171== by 0x702F09F: ??? (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0) 
==7171== by 0x702F2E7: ??? (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0) 
==7171== by 0x702EB50: ASN1_item_ex_d2i (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0) 
==7171== by 0x702F09F: ??? (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0) 
==7171== by 0x702F2E7: ??? (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0) 
==7171== 
OK (3) 
==7171== 
==7171== HEAP SUMMARY: 
==7171==  in use at exit: 64 bytes in 2 blocks 
==7171== total heap usage: 10,535 allocs, 10,533 frees, 898,726 bytes allocated 
==7171== 
==7171== 32 bytes in 1 blocks are still reachable in loss record 1 of 2 
==7171== at 0x4C2B3F8: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==7171== by 0x6F821FF: CRYPTO_malloc (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0) 
==7171== by 0x700A82E: sk_new (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0) 
==7171== by 0x6D012A9: ??? (in /lib/x86_64-linux-gnu/libssl.so.1.0.0) 
==7171== by 0x6D031F8: SSL_COMP_get_compression_methods (in /lib/x86_64-linux-gnu/libssl.so.1.0.0) 
==7171== by 0x6D08618: SSL_library_init (in /lib/x86_64-linux-gnu/libssl.so.1.0.0) 
==7171== by 0x549A1E2: ??? (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.2.0) 
==7171== by 0x54A1B89: curl_global_init (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.2.0) 
==7171== by 0x559240: RCC::IO::HttpClient::get(std::string) (HttpClient.cpp:53) 
==7171== by 0x559FFE: HttpClientTest::testBasicRequest() (HttpClientTest.cpp:55) 
==7171== by 0x55BB11: CppUnit::TestCaller<HttpClientTest>::runTest() (TestCaller.h:166) 
==7171== by 0x56FA081: CppUnit::TestCaseMethodFunctor::operator()() const (in /usr/lib/libcppunit-1.12.so.1.0.0) 
==7171== 
==7171== 32 bytes in 1 blocks are still reachable in loss record 2 of 2 
==7171== at 0x4C2B3F8: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==7171== by 0x6F821FF: CRYPTO_malloc (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0) 
==7171== by 0x700A84C: sk_new (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0) 
==7171== by 0x6D012A9: ??? (in /lib/x86_64-linux-gnu/libssl.so.1.0.0) 
==7171== by 0x6D031F8: SSL_COMP_get_compression_methods (in /lib/x86_64-linux-gnu/libssl.so.1.0.0) 
==7171== by 0x6D08618: SSL_library_init (in /lib/x86_64-linux-gnu/libssl.so.1.0.0) 
==7171== by 0x549A1E2: ??? (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.2.0) 
==7171== by 0x54A1B89: curl_global_init (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.2.0) 
==7171== by 0x559240: RCC::IO::HttpClient::get(std::string) (HttpClient.cpp:53) 
==7171== by 0x559FFE: HttpClientTest::testBasicRequest() (HttpClientTest.cpp:55) 
==7171== by 0x55BB11: CppUnit::TestCaller<HttpClientTest>::runTest() (TestCaller.h:166) 
==7171== by 0x56FA081: CppUnit::TestCaseMethodFunctor::operator()() const (in /usr/lib/libcppunit-1.12.so.1.0.0) 
==7171== 
==7171== LEAK SUMMARY: 
==7171== definitely lost: 0 bytes in 0 blocks 
==7171== indirectly lost: 0 bytes in 0 blocks 
==7171==  possibly lost: 0 bytes in 0 blocks 
==7171== still reachable: 64 bytes in 2 blocks 
==7171==   suppressed: 0 bytes in 0 blocks 
==7171== 
==7171== For counts of detected and suppressed errors, rerun with: -v 
==7171== Use --track-origins=yes to see where uninitialised values come from 
==7171== ERROR SUMMARY: 4 errors from 1 contexts (suppressed: 2 from 2) 

Завиток обертка (существенная часть):

static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) 
{ 
    ((std::string*)userp)->append((char*)contents, size * nmemb); 
    return size * nmemb; 
} 

std::string HttpClient::get(std::string url) 
{ 
    curl_global_init(CURL_GLOBAL_ALL); 

    CURL *curl = NULL; 
    CURLcode result; 
    std::string readBuffer = ""; 

    curl = curl_easy_init(); 

    if (curl == 0) 
     throw std::runtime_error("Unable to create CURL instance"); 

    if (useProxy) 
     curl_easy_setopt(curl, CURLOPT_PROXY, proxyHost.c_str()); 

    if (useAuth) 
     authenticate(curl);  

    if (followRedirect) 
     curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); 


    LOG_DEBUG("http client fetch " + url);  

    curl_easy_setopt(curl, CURLOPT_URL, url.c_str());  
    curl_easy_setopt(curl, CURLOPT_POST, false); 
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); 
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); 

    result = curl_easy_perform(curl); 

    if (result != CURLE_OK) { 
     curl_easy_cleanup(curl); 
     throw std::runtime_error(curl_easy_strerror(result)); 
    } 

    curl_easy_cleanup(curl);   
    curl_global_cleanup(); 

    return readBuffer; 
} 

Запуск тестов с:

valgrind --leak-check=full --show-reachable=yes -v ./tests/testsuite 
+0

Да для меня достаточно 64 байт, чтобы жаловаться. Где ваш лимит. Я не знаю, будет ли он умножаться на несколько вызовов. Я не знаю, правильна ли моя очистка. Поэтому я задаю вопрос. Неужели это так плохо? – jami

+4

Проблема может заключаться в том, что OpenSSL динамически распределяет некоторые данные при загрузке и использует эти данные для времени жизни процесса. Некоторый тип данных для каждого процесса (или для потоковой четности). Поскольку предполагается, что он будет использоваться в течение всего жизненного цикла процесса, нет необходимости его освобождать, так как он будет выполняться операционной системой, когда процесс завершится. –

ответ

0

Хорошо, я принимаю хороший ответ от Joachim Pileborg (комментарий под главный вопрос). OpenSSL использует некоторые данные для каждого процесса, который выдерживает жизненный цикл моей программы. Таким образом, valgrind обнаруживает, что он все еще доступен, и моя инициализация/завершение OpenSSL кажется правильной. Спасибо Joachim

Смежные вопросы