如何使用curl + ssl没有内存泄漏灾难

How to use curl + ssl without memleak disaster

本文关键字:内存 泄漏 何使用 curl ssl      更新时间:2023-10-16

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

如果我禁用SSL与curl_global_init(CURL_GLOBAL_NOTHING)没有memleaks被检测到。但是也没有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)

curl包装器(它的重要部分):

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

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