Я написал простую обертку для завивки, чтобы получить доступ к содержимому 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
Да для меня достаточно 64 байт, чтобы жаловаться. Где ваш лимит. Я не знаю, будет ли он умножаться на несколько вызовов. Я не знаю, правильна ли моя очистка. Поэтому я задаю вопрос. Неужели это так плохо? – jami
Проблема может заключаться в том, что OpenSSL динамически распределяет некоторые данные при загрузке и использует эти данные для времени жизни процесса. Некоторый тип данных для каждого процесса (или для потоковой четности). Поскольку предполагается, что он будет использоваться в течение всего жизненного цикла процесса, нет необходимости его освобождать, так как он будет выполняться операционной системой, когда процесс завершится. –