Я унаследовал некоторый устаревший код, и кажется, что где-то произошла утечка памяти. Мой первый инстинкт был просто скомпилировать
-faddress=sanitize -fno-omit-frame-pointer
и позвольте семейству инструментов Address Sanitizer найти утечку для меня. Однако я был сильно разочарован. Я надеялся на какое-то сообщение об ошибке во время выполнения (похоже на ошибку адресного очистителя, когда вы не читаете или не записываете память). Дезинфицирующее средство для устранения утечек, по-видимому, не выполняет никакого анализа на предмет утечки до тех пор, пока программа не будет успешно завершена. Моя проблема в том, что у меня в наследстве есть несколько потоков, и он не предназначен для объединения их всех в рамках подготовки к мягкой посадке.
Я упростил свою проблему на простом примере:
#include <thread>
#include <chrono>
#include <iostream>
bool exit_thread = false;
void threadFunc()
{
while(!exit_thread)
{
char* leak = new char[256];
std::this_thread::sleep_for(std::chrono::seconds{1});
}
}
int main() {
std::thread t(threadFunc);
std::cout << "Waiting\n";
std::this_thread::sleep_for(std::chrono::seconds{5});
exit_thread = true;
std::cout << "Exiting\n";
//Without joining here I do not get the leak report.
t.join();
return 0;
}
Я собираю это с
clang++ leaker.cpp -fsanitize=address -fno-omit-frame-pointer -g -O0 -std=c++1y -o leaker
А потом побежал с
ASAN_OPTIONS='detect_leaks=1' LSAN_OPTIONS='exitcode=55:report_objects=true:log_threads=true:log_pointers=true' ./leaker
(Я как-то с ума сошел о «LSAN_OPTIONS» здесь, потому что я играл вокруг … ни один из вариантов не сделал то, что я хотел, а должен был выйти после обнаружения утечки).
Как отмечено в коде, если я присоединяюсь к потоку, а затем выхожу из программы, я получаю довольно отчет об утечке. Иначе я ничего не получу. Как вы можете отслеживать 10-100 потоков в устаревшей кодовой базе а также заставить их всех упасть, это громоздко.
Несколько лет назад я помню, как играл с Визуальный детектор утечки и мне повезло с этим, потому что он генерировал бы отчеты со всеми потенциальными утечками памяти (и я не помнил, чтобы все было красиво снято). Проблема в том, что этот инструмент предназначен только для Windows, а мой код работает только на Linux. Можно ли заставить инструмент LeakSanitizer сделать что-то подобное?
Публичный интерфейс LeakSanitizer (дезинфицирующее / lsan_interface.h) имеет различные функции, которые могут соответствовать вашим потребностям. функция __lsan_do_leak_check()
выполняет проверку и прекращает работу при обнаружении утечки. Существует также __lsan_do_recoverable_leak_check
который не заканчивается и может быть вызван несколько раз.
Рассмотрим эту модификацию вашей программы:
#include <thread>
#include <chrono>
#include <iostream>
#include <sanitizer/lsan_interface.h>
bool exit_thread = false;
void threadFunc()
{
while(!exit_thread)
{
char* leak = new char[256];
std::this_thread::sleep_for(std::chrono::seconds{1});
}
}
int main() {
std::thread t(threadFunc);
std::cout << "Waiting\n";
std::this_thread::sleep_for(std::chrono::seconds{5});
exit_thread = true;
std::cout << "Exiting\n";
//Without joining here I do not get the leak report.
//t.join();
__lsan_do_recoverable_leak_check();
std::cout << "Done\n";
return 0;
}
Выход:
Waiting
Exiting
=================================================================
==29240==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 1024 byte(s) in 4 object(s) allocated from:
#0 0x4d9a30 in operator new[](unsigned long) (leaker+0x4d9a30)
#1 0x4dc663 in threadFunc() leaker.cpp:12:20
#2 0x4dffe3 in void std::_Bind_simple<void (*())()>::_M_invoke<>(std::_Index_tuple<>) /usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/functional:1530:18
#3 0x4dff94 in std::_Bind_simple<void (*())()>::operator()() /usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/functional:1520:16
#4 0x4dfcc8 in std::thread::_Impl<std::_Bind_simple<void (*())()> >::_M_run() /usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/thread:115:13
#5 0x7f0a9664034f in execute_native_thread_routine /build/gcc-multilib/src/gcc-5.2.0/libstdc++-v3/src/c++11/thread.cc:84
SUMMARY: AddressSanitizer: 1024 byte(s) leaked in 4 allocation(s).
Done
terminate called without an active exception
Aborted
Других решений пока нет …