2016-05-14 4 views
2

ОС: Linux/Debian/Sid/x86_64 (и Linux/Debian/тестирование/x86_64); моя система GCC, используемая для компиляции, - 6.1.1 (и 5.3 с Debian/Testing). Gnu libc - 2,22; Ядро Linux - 4,5; GDB является системой 7,10 или мой собственный, построенный из источника FSF, 7,11охота (память, связанная с GC) heisenbug исчезает без ASLR

Я охочусь (так как почти две недели) память & garbage collection связанных heisenbug в MELT экспериментальной ветви НКИ (MELT грубо говоря лисповский -как домена конкретного языка, чтобы настроить GCC компилятор, расплавом диалект переведен на C++ с использованием самого Растопить), который можно восстановить с

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 имеет поколения копирование сборщика мусора (и я подозреваю, что ошибка будет угловой случаем в нем) и использует лот metaprogramming (в частности, большинство кодов сканирования и пересылки для копирования GC генерируется MELT).

(valgrind здесь не поможет: мы реализации копировального GC, а сам GCC является -Дажа без утечки памяти талой)

MELT загрузилось. Обычная процедура сборки регенерирует дважды испускаемый код C++ из исходного кода MELT. Обычный способ состоит в том, чтобы испускать некоторый код на C++, fork some make, чтобы получить общий объект, и dlopen, что и общий объект, и снова.

БезASLR, сборка всегда успех (и это работает значительное испытание: начальной загрузки талой и анализ РАСПЛАВНЫХ выполнения путем компиляции расширенной талой). И я мог бы даже восстановить код времени выполнения с помощью make upgrade-warmelt.

Но с ASLR включена, сборка не удается, сбой всегда таким же образом (заметьте, что cc1plus является MELT один):

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; и, конечно, при запуске uder gdb ASLR отключен по умолчанию (если только я не делаю set disable-randomization 0 в качестве команды GDB).

Мой коллега Франк Ведрин предложил мне использовать reverse execution объекты gdb; в принципе, это должно быть так же просто, как установить контрольную точку в моем GC (и в 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 значение) в редком случае, когда этот дискриминант все еще находится в молодом поколении ... Добавляя некоторый код, чтобы избежать этого, действительно, ошибка произошла позже, но я совсем не уверен.

Любые подсказки или рекомендации по отладке гейзенбуга, связанного с фактическими виртуальными адресами (отсюда разумный для ASLR!), Приветствуются.

Я даже добавил некоторый код инициализации, чтобы иметь возможность необязательноmmap или sbrk несколько мегабайта бесполезного, в надежде «воспроизвести» рандомизированный адрес, выданный mmap (вызывается calloc используемого расплава и его GC). Это еще не помогло!

ответ

2

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

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

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

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

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

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

+0

Я не могу сказать, сможет ли Базиле использовать эту технику для хорошего использования, но я могу сказать, что это умная техника. –

 Смежные вопросы

  • Нет связанных вопросов^_^