Отследить повреждение кучи, выделяя много памяти? - PullRequest
0 голосов
/ 31 октября 2019

В моей программе я сталкиваюсь со следующей ошибкой:

free(): invalid size
Aborted (core dumped)

Запуск GDB Я обнаружил, что это происходит в деструкторе вектора:

#0  0x00007ffff58e8c01 in free () from /lib/x86_64-linux-gnu/libc.so.6
#1  0x0000555555dd44e2 in __gnu_cxx::new_allocator<int>::deallocate (this=0x7fffffff6bf0, __p=0x555557117810) at /usr/include/c++/7/ext/new_allocator.h:125
#2  0x0000555555dcfbd7 in std::allocator_traits<std::allocator<int> >::deallocate (__a=..., __p=0x555557117810, __n=1) at /usr/include/c++/7/bits/alloc_traits.h:462
#3  0x0000555555dc85e6 in std::_Vector_base<int, std::allocator<int> >::_M_deallocate (this=0x7fffffff6bf0, __p=0x555557117810, __n=1)
    at /usr/include/c++/7/bits/stl_vector.h:180
#4  0x0000555555dc49e1 in std::_Vector_base<int, std::allocator<int> >::~_Vector_base (this=0x7fffffff6bf0, __in_chrg=<optimized out>)
    at /usr/include/c++/7/bits/stl_vector.h:162
#5  0x0000555555dbc5c9 in std::vector<int, std::allocator<int> >::~vector (this=0x7fffffff6bf0, __in_chrg=<optimized out>) at /usr/include/c++/7/bits/stl_vector.h:435
#6  0x0000555556338081 in Gambit::Printers::HDF5Printer2::get_buffer_idcodes[abi:cxx11](std::vector<Gambit::Printers::HDF5MasterBuffer*, std::allocator<Gambit::Printers::HDF5MasterBuffer*> > const&) (this=0x555556fd8820, masterbuffers=...) at /home/farmer/repos/gambit/copy3/Printers/src/printers/hdf5printer_v2/hdf5printer_v2.cpp:2183

где эта последняя строкакод просто:

std::vector<int> alllens(myComm.Get_size());

Итак, во-первых, я не совсем понимаю, почему здесь вызывается деструктор, но предположим, что это нормальная часть динамического построения вектора, тогда я думаю, что эта ошибка должна бытьиз-за какой-то кучи коррупции.

Я не совсем понимаю, хотя, является ли идея, что какая-то другая часть кода ранее незаконно получила доступ к памяти, которая должна быть выделена для этого вектора?

Во-вторых,Я попытался запустить это через Intel Inspector, и у меня действительно есть куча проблем «Неправильный доступ к памяти» и «Неинициализированный доступ к памяти», но все они выглядят как ложные срабатывания в библиотеках, которые я использую, например, HDF5.

Есть ли какой-то внутрикодовый способ сузить, откуда именно проблема? Например, поскольку это вызвано динамическим распределением памяти, могу ли я просто начать выделять огромные массивы раньше и раньше в коде, чтобы попытаться вызвать сбой ближе к месту его возникновения? Я пытался найти, будет ли что-то подобное работать или быть полезным, но ничего не нашел, так что, может быть, это не очень хорошая идея?

1 Ответ

0 голосов
/ 05 ноября 2019

Так что оказалось, что я испортил кучу через некоторые подпрограммы MPI, то есть неверные параметры для длины буфера и так далее. К сожалению, в библиотеках MPI происходит много сумасшедших вещей, поэтому анализаторы памяти, такие как Intel Inspector, не очень пригодились для его поиска.

Однако я узнал о Address Sanitizer (https://en.wikipedia.org/wiki/AddressSanitizer), который поставляется с современнымиКомпиляторы GNU, и это оказалось здорово! Скомпилировано с ним в моем проекте CMake (из https://gist.github.com/jlblancoc/44be9d4d466f0a973b1f3808a8e56782)

cmake .. -DCMAKE_CXX_FLAGS="-fsanitize=address  -fsanitize=leak -g" 
  -DCMAKE_C_FLAGS="-fsanitize=address  -fsanitize=leak -g"
  -DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address  -fsanitize=leak"
  -DCMAKE_MODULE_LINKER_FLAGS="-fsanitize=address  -fsanitize=leak"

Запустил его с

export ASAN_OPTIONS=fast_unwind_on_malloc=0

(Не знаю, было ли этодействительно необходимо), и получил фантастический след, когда произошло повреждение моей кучи:

==12748==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000521340 at pc 0x7fda5011577a bp 0x7ffe231c55e0 sp 0x7ffe231c4d88
WRITE of size 32 at 0x602000521340 thread T0
    #0 0x7fda50115779  (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x79779)
    #1 0x7fda4fcd84e3  (/usr/lib/x86_64-linux-gnu/libmpich.so.0+0xf24e3)
    #2 0x7fda4fc228d7  (/usr/lib/x86_64-linux-gnu/libmpich.so.0+0x3c8d7)
    #3 0x7fda4fc23a26  (/usr/lib/x86_64-linux-gnu/libmpich.so.0+0x3da26)
    #4 0x7fda4fc2316c  (/usr/lib/x86_64-linux-gnu/libmpich.so.0+0x3d16c)
    #5 0x7fda4fc2406c in PMPI_Gather (/usr/lib/x86_64-linux-gnu/libmpich.so.0+0x3e06c)
    #6 0x55e0c18586b0 in void Gambit::GMPI::Comm::Gather<unsigned long>(std::vector<unsigned long, std::allocator<unsigned long> >&, std::vector<unsigned long, std::allocator<unsigned long> >&, int) /home/farmer/repos/gambit/copy3/Utils/include/gambit/Utils/mpiwrapper.hpp:450
    ...etc... 

Это указывало прямо на вызов MPI, который я облажался. Удивительно!

Но чтобы ответить на мой вопрос OPМоя идея выделить много памяти кучи, чтобы вызвать сбой ближе к проблеме, на самом деле не работала. Не знаю почему. Наверное, я просто не понимаю, что там происходит под капотом. На самом деле, место, где я былвидеть, что сбой был до вызова MPI в моем коде, так что это было довольно странно. Я думаю, компилятор переместил некоторые вещи? У меня были оптимизациивыключен, но я полагаю, что операции в двоичном файле все равно можно было бы упорядочить иначе, чем я ожидал?

...