如何在没有memleak灾难的情况下使用curl + ssl

时间:2014-05-14 09:46:59

标签: c++ c valgrind libcurl

我编写了一个简单的curl get包装器来访问http,https内容。如果我用valgrind运行我的测试用例,我可以看到一些仍然可以访问的扇区。是的我知道他们并不像丢失的参考文献那样邪恶或者绝对丢失。但我想保持我的项目清洁。

如果我使用curl_global_init(CURL_GLOBAL_NOTHING)禁用SSL,则不会检测到memleak。但此后也没有https支持。所以我猜它是一个libcrypt,libssl问题?如果没有valgrind通知,我该怎么做才能正确初始化和清理https curl调用?

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)

卷曲包装(它的基本部分):

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

1 个答案:

答案 0 :(得分:0)

好的,我接受Joachim Pileborg的好答案(根据主要问题发表评论)。 OpenSSL使用每个进程的一些数据,这些数据在我的程序生命周期中存活。所以valgrind检测到它仍然可以访问,我的OpenSSL初始化/终结似乎是正确的。谢谢Joachim