Question

I have written a simple curl get wrapper to access http, https content. If I run my testcases with valgrind, I can see some still reachable sectors. Yes I know they are not as evil as lost references or definitely losts. But i want to keep my project clean.

If I disable SSL with curl_global_init(CURL_GLOBAL_NOTHING) no memleaks are detected. But then there is also no https support. So I guess its a libcrypt, libssl problem? What can I do to initialize and cleanup a https curl call correctly without having valgrind notifications?

jami@jami-mbp: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)

The curl wrapper (essential part of it):

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;
}

Run the tests with:

valgrind --leak-check=full --show-reachable=yes -v ./tests/testsuite
Était-ce utile?

La solution

Ok, I accept the good answer from Joachim Pileborg (a comment under the main question). OpenSSL use some data per process which survives the lifecycle of my program. So valgrind detect it as still reachable and my OpenSSL initialization/finalization seems to be correct. Thank you Joachim

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top