Ruby / Glibc coredump (double free или corruption)
Я использую инструмент распределенной непрерывной интеграции, который я написал сам в Ruby. Он использует вилку "политики" Майка Перхама для распределения задач. Модуль "политика" использует потоки для части mDNS.
Время от времени я сталкиваюсь с дампом ядра, который я не понимаю:
*** glibc detected *** ruby: double free or corruption (fasttop): 0x086d8600 ***
======= Backtrace: =========
/lib/libc.so.6[0xb7cef494]
/lib/libc.so.6[0xb7cf0b93]
/lib/libc.so.6(cfree+0x6d)[0xb7cf3c7d]
/usr/lib/libruby18.so.1.8[0xb7e8adf8]
/usr/lib/libruby18.so.1.8(ruby_xmalloc+0x85)[0xb7e8b395]
/usr/lib/libruby18.so.1.8[0xb7e5065e]
...
/usr/lib/libruby18.so.1.8[0xb7e717f4]
/usr/lib/libruby18.so.1.8[0xb7e74296]
/usr/lib/libruby18.so.1.8(rb_yield+0x27)[0xb7e7fb57]
======= Memory map: ========
...
Я работаю на Gentoo и перестроил Ruby и Glibc с "- GDB " и отключил чередование, чтобы получить осмысленное ядро:
...
Core was generated by `ruby /home/develop/dcc/bin/dcc-worker'.
Program terminated with signal 6, Aborted.
#0 0xb7f20410 in __kernel_vsyscall ()
(gdb) bt
#0 0xb7f20410 in __kernel_vsyscall ()
#1 0xb7cacb60 in *__GI___open_catalog (cat_name=0x6 <Address 0x6 out of bounds>, nlspath=0xbf9d6f00 " ", env_var=0x0, catalog=0x1) at open_catalog.c:237
#2 0xb7cae498 in __sigdelset (set=0x6) from /lib/libc.so.6
#3 *__GI_sigfillset (set=0x6) at ../signal/sigfillset.c:42
#4 0xb7ce952d in freopen64 (filename=0x2 <Address 0x2 out of bounds>, mode=0xb7db02c8 "" total="%zu" count="%zu"/>n", fp=0x9) at freopen64.c:47
#5 0xb7cef494 in _IO_str_init_readonly (sf=0x86d8600, ptr=0xb7eef5a9 "te213Vb20532217204220", size=-1210273804) at strops.c:88
#6 0xb7cf0b93 in mALLINFo (av=0xb) at malloc.c:5865
#7 0xb7cf3c7d in __libc_calloc (n=141395456, elem_size=3214793136) at malloc.c:4019
#8 0xb7e8adf8 in ?? () at gc.c:1390 from /usr/lib/libruby18.so.1.8
#9 0x086d8600 in ?? ()
#10 0xb7e89400 in rb_gc_disable () at gc.c:256
#11 0xb7e8b395 in add_freelist () at gc.c:1087
#12 gc_sweep () at gc.c:1186
#13 garbage_collect () at gc.c:1524
#14 0xb7e5065e in ?? () from /usr/lib/libruby18.so.1.8
#15 0x00000340 in ?? ()
#16 0x00000000 in ?? ()
(gdb)
Хм??? Для меня это выглядит так как будто это полностью Руби интерн. На других" двойных свободных или коррупционных " проблемах здесь, в stackoverflow, я видел, что, возможно, потоки являются частью проблемы.
Также проблема не возникает в точно такой же позиции. У меня есть еще один обратный путь, который намного длиннее, но крах также находится в garbage_collect, но с немного другим путем:
(gdb) bt
#0 0xffffe430 in __kernel_vsyscall ()
#1 0xf7c8b8c0 in *__GI_raise (sig=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
#2 0xf7c8d1f5 in *__GI_abort () at abort.c:88
#3 0xf7cc7e35 in __libc_message (do_abort=2, fmt=0xf7d8daa8 "*** glibc detected *** %s: %s: 0x%s ***n") at ../sysdeps/unix/sysv/linux/libc_fatal.c:170
#4 0xf7ccdd24 in malloc_printerr (action=2, str=0xf7d8dbec "double free or corruption (fasttop)", ptr=0x911f5d0) at malloc.c:6197
#5 0xf7ccf403 in _int_free (av=0xf7daa380, p=0x911f5c8) at malloc.c:4750
#6 0xf7cd24ad in *__GI___libc_free (mem=0x911f5d0) at malloc.c:3716
#7 0xf7e68768 in obj_free () at gc.c:1366
#8 gc_sweep () at gc.c:1174
#9 garbage_collect () at gc.c:1524
#10 0xf7e68be5 in rb_newobj () at gc.c:436
#11 0xf7eb9840 in str_alloc (klass=0) at string.c:67
... (150 lines of rb_eval/call/yield etc.)
Есть ли у кого-нибудь предложения, как изолировать и, возможно, решить эту проблему?4 ответа:
Быстро, легко и не так полезно:
export MALLOC_CHECK_=2. Это заставляет glibc выполнять дополнительный уровень проверки во времяfree(), чтобы избежать повреждения кучи. Он будетabort()и даст дамп ядра, как только обнаружит коррупцию, вместо того, чтобы ждать, пока не возникнет реальная проблема, вызванная коррупцией.Не так быстро и легко, но гораздо полезнее (если вы заставите его работать): valgrind.
Valgrind позволяет легко находить проблемы повреждения кучи. Есть некоторые ложные ошибки, сообщаемые при использовании Ruby 1.8 под valgrind, но они могут быть устранены с помощью этого Ruby patch (и настройки с --enable-valgrind) или с помощью файла подавления valgrind. Чтобы запустить программу ruby под управлением valgrind, просто добавьте в команду префикс
valgrind:valgrind ruby /home/develop/dcc/bin/dcc-workerЕсли процесс сбоя является дочерним по отношению к запущенному процессу, используйте
valgrind --trace-children=yes. Обратите особое внимание на недопустимые записи , которые являются признаком повреждения кучи.
Я получил ту же самую ошибку в простой программе " C " под названием rd_test; она просто считывала заданное число байт, используя read (2) из заданного входного файла (может быть файл устройства).
фактическая ошибка оказалась переполнением буфера на 1 байт (как и я ... buf[n]= '\0'; ... где ' n '- количество байт, считанных в буфер 'buf'). Глупый я.
Но дело в том, что я никогда не ловил его, пока не пробежал его с валгриндом! Так что ИМХО валгринд определенно стоит занимаюсь подобными делами.Ошибка "double free or corruption" исчезла, как только я избавился от оскорбительной ошибки.