ОС: Linux / Debian / Sid / x86_64 (и Linux / Debian / Testing / x86_64); моя система GCC, используемая для компиляции, — это 6.1.1 (и 5.3 с Debian / Testing). Gnu libc составляет 2,22; Ядро Linux — 4.5; GDB — это система 7.10 или моя собственная, собранная из источника FSF, 7.11
Я охочусь (так как почти две недели) воспоминание & вывоз мусора связанные с гейзенбаг в ПЛАВИТЬСЯ экспериментальная ветвь GCC (MELT грубо говорит на языке, подобном Lisp, для настройки компилятора GCC; диалект MELT переводится на C ++ с использованием самого MELT), который вы можете получить с помощью
svn co -r236207 svn://gcc.gnu.org/svn/gcc/branches/melt-branch gcc-melt
затем (как для каждого варианта или ветви GCC) встроить его в вне дерево, например
mkdir _ObjMelt
cd _ObjMelt
../gcc-melt/configure --disable-bootstrap --enable-checks=gc \
--enable-plugins --disable-multilib --enable-languages=c,c++,lto
(вы можете передать другие варианты ../gcc-melt/configure
например, CXXFLAGS='-g3 -O0 -DMELT_HAVE_RUNTIME_DEBUG=1'
если ты хотел; Вы можете удалить --enable-checks=gc
опция)
и конечно make
(или же make -j4
); эта сборка может занять более получаса (и, вероятно, потерпит неудачу с ASLR, см. ниже)
MELT имеет поколение копирование сборщик мусора (и я подозреваю, что ошибка является ключевым в нем) и использует много метапрограммированием (в частности, большая часть кодов сканирования и пересылки для копирующего GC генерируется MELT).
(valgrind
не поможет здесь: мы реализации копирующий GC, а сам GCC — даже без MELT — утечка памяти)
MELT загружается. Обычная процедура сборки восстанавливает вдвое испускаемый код C ++ из исходного кода MELT. Обычный способ — создать код на C ++ make
чтобы получить общий объект, и dlopen
этот общий объект, и снова.
Без ASLR, сборка всегда выполняется успешно (и она выполняет значительный тест: загрузчик MELT и анализ среды выполнения MELT с помощью компиляции, расширенной MELT). И я мог бы даже восстановить код времени выполнения с make upgrade-warmelt
,
Но с включенным ASLR, сборка не удалась, грохот всегда в том же порядке (обратите внимание, что cc1plus
тает один):
cc1plus: note: MELT got fatal failure from ../../gcc-melt/gcc/melt-runtime.h:900
cc1plus: fatal error: corrupted memory heap with null magic discriminant
in 0x2bab6a8; GC#11
compilation terminated.
MELT BUILD SCRIPT FAILURE:
melt-build-script.tpl:382/307-melt-build-script.tpl:459/382 failed
with arguments @meltbuild-stage2/warmelt-normatch.args
Я отключаю ASLR, например с exec setarch $(uname -m) -R /bin/bash
; ну и конечно же при беге gdb
ASLR отключен по умолчанию (если я не сделаю set disable-randomization 0
как команда GDB).
Мой коллега Франк Ведрин предложил мне использовать обратное исполнение объекты gdb
; в принципе, это должно быть так же просто, как установить точку останова в моем ГХ (и в fatal_error
& melt_fatal_info
называется melt_fatal_error
макрос …), достичь GC#11
состояние, сделать record
для последующего выполнения в обратном порядке запустите ошибочный случай (с помощью set disable-randomization 0
отключить ASLR) до «сбоя», затем reverse-cont
до точки останова в GC, и использовать watch
с умом. К сожалению, это вызывает широкое известная ошибка GDB (Sourceware # 19365, Ubuntu # 1573786, Redhat # 1136403, …) — что недавние снимки GDB нравятся gdb-7.11.50.20160514
не правильно-
(Теперь я испытываю желание избежать этой ошибки GDB, возможно, имея свой собственный memset
& memcpy
подпрограммы с #pragma GCC optimize ("-Og")
до них; но это выглядит слишком далеко)
Для чего это стоит, сообщение о сбое дается следующим кодом (около строки 900 моего melt-runtime.h
):
static inline int
melt_magic_discr (melt_ptr_t p)
{
if (!p)
return 0;
#if MELT_HAVE_DEBUG > 0 || MELT_HAVE_RUNTIME_DEBUG > 0
if (MELT_UNLIKELY(!p->u_discr))
{
/* This should never happen, we are asking the discriminant of a
not yet filled, since cleared, memory zone. */
melt_fatal_error
("corrupted memory heap with null discriminant in %p; GC#%ld",
(void*) p, melt_nb_garbcoll);
}
#endif /*MELT_HAVE_DEBUG or MELT_HAVE_RUNTIME_DEBUG */
gcc_assert (p->u_discr != NULL);
return p->u_discr->meltobj_magic;
}
Я предполагаю, что ошибка может быть трудной ошибкой GC при пересылке «дискриминанта» (своего рода поля «тип» или «класс» или «метаданные» в каждый Значение MELT) в редком случае, когда этот дискриминант все еще находится в молодом поколении … Добавление некоторого кода, чтобы избежать этого, действительно привело к тому, что ошибка произошла позже, но я совсем не уверен.
Любые подсказки или советы по отладке heisenbug, относящиеся к фактическим виртуальным адресам (следовательно, разумным для ASLR!), Приветствуются.
Я даже добавил код инициализации, чтобы иметь возможность по выбору mmap
или же sbrk
несколько бесполезных мегабайт, надеясь «воспроизвести» случайный адрес, заданный mmap
(вызывается calloc
используется MELT и его GC). Это еще не помогло!
подход, который я использовал в своем сборщике мусора Smalltalk, состоит в том, чтобы скопировать кучу перед каждым сборщиком мусора и выполнить сборку мусора в копии, а затем повторить отладку в случае сбоя копии. Это относительно тривиально, если система, как и моя, разработана на высокоуровневом языке; Копирование кучи — это просто копирование графа объектов, составляющих симуляцию виртуальной машины (а в симуляции куча находится в одном большом байтовом массиве).
Применение этого метода в вашем контексте, вероятно, будет значительно более сложным, но не должно быть невозможным. Позвольте мне набросать это здесь …
Я назову процесс, который вы пытаетесь отладить, «хозяином» и теми, которые клонированы, чтобы попробовать GC для него, детьми.
Перед GC в мастере, сделайте разветвление и попросите ребенка выполнить GC, запустив проверку утечки в дочернем устройстве и выйдя со статусом выхода, отражающим, успешно или нет GC. Затем мастер продолжает свой собственный GC, если ребенок преуспел. В противном случае это циклы, порождающие детей, которые повторяют неудачный GC. Затем вы отлаживаете ребенка.
Ребенок должен быть запущен в двух штатах. Первоначальный запуск в каждом ГХ просто запускает ГХ и завершает работу со статусом успеха. Последующие вилки, которые мы теперь знаем, потерпят неудачу, могут перейти в состояние ожидания, чтобы вы могли присоединить gdb к ребенку.
Я называю это «отладкой лемминга», поскольку можно прыгать через скалу столько клонов, сколько нужно, до тех пор, пока сбой не будет отлажен. Дайте мне знать, если у вас получится.
Других решений пока нет …