охота (память, связанный с GC), исчезновение гейзенбаг без ASLR

ОС: 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). Это еще не помогло!

2

Решение

подход, который я использовал в своем сборщике мусора Smalltalk, состоит в том, чтобы скопировать кучу перед каждым сборщиком мусора и выполнить сборку мусора в копии, а затем повторить отладку в случае сбоя копии. Это относительно тривиально, если система, как и моя, разработана на высокоуровневом языке; Копирование кучи — это просто копирование графа объектов, составляющих симуляцию виртуальной машины (а в симуляции куча находится в одном большом байтовом массиве).

Применение этого метода в вашем контексте, вероятно, будет значительно более сложным, но не должно быть невозможным. Позвольте мне набросать это здесь …

Я назову процесс, который вы пытаетесь отладить, «хозяином» и теми, которые клонированы, чтобы попробовать GC для него, детьми.

Перед GC в мастере, сделайте разветвление и попросите ребенка выполнить GC, запустив проверку утечки в дочернем устройстве и выйдя со статусом выхода, отражающим, успешно или нет GC. Затем мастер продолжает свой собственный GC, если ребенок преуспел. В противном случае это циклы, порождающие детей, которые повторяют неудачный GC. Затем вы отлаживаете ребенка.

Ребенок должен быть запущен в двух штатах. Первоначальный запуск в каждом ГХ просто запускает ГХ и завершает работу со статусом успеха. Последующие вилки, которые мы теперь знаем, потерпят неудачу, могут перейти в состояние ожидания, чтобы вы могли присоединить gdb к ребенку.

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

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]