4

我正在使用我自己用 Ruby 编写的分布式持续集成工具。它使用 Mike Perham 的“政治”的一个分支来分配任务。“politics”模块正在为 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 上运行并使用“-gdbg”重建了 Ruby 和 Glibc,并关闭了条带化以获得有意义的核心:

...
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 "te\213V\b\205\322\017\204\220", 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) 

唔???对我来说,这看起来完全是 Ruby 实习生。关于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

4 回答 4

6

快速,简单,但没有那么有用:export MALLOC_CHECK_=2. 这会导致 glibc 在 期间进行一些额外的检查free(),以避免堆损坏。它会abort()在检测到损坏后立即提供核心转储,而不是等到损坏导致实际问题出现。

不是那么快速和简单,但更有帮助(如果你让它工作的话):valgrind

于 2010-02-15T20:45:27.080 回答
2

Valgrind使查找堆损坏问题变得容易。在 valgrind 下使用 Ruby 1.8 时报告了一些虚假错误,但可以使用此 ruby​​ 补丁(并使用 --enable-valgrind 配置)或使用valgrind 抑制文件来消除它们。要在 valgrind 下运行 ruby​​ 程序,只需在命令前加上valgrind

valgrind ruby /home/develop/dcc/bin/dcc-worker

如果崩溃进程是您正在运行的进程的子进程,请使用valgrind --trace-children=yes. 特别注意无效写入,这是堆损坏的标志。

于 2010-02-15T23:18:26.283 回答
1

我在一个名为 rd_test 的简单“C”程序中遇到了同样的错误;它只会使用 read(2) 从给定的输入文件(可能是设备文件)中读取给定数量的字节。

实际的错误结果是 1 个字节的缓冲区溢出(就像我所做的那样... buf[n]='\0'; ... 其中 'n' 是读入缓冲区 'buf' 的字节数) . 傻我。

但是,问题是在我用 valgrind 运行它之前,我从来没有发现它!所以恕我直言,valgrind 绝对值得在这样的情况下运行。

The 'double free or corruption' error went away as soon as i got rid of the offending bug.

于 2011-01-29T12:39:01.723 回答
0

我收到了相同的错误消息,不是在 ruby​​ 中,而是在 zenity-program 中。我发现这与我关闭了两次打开的管道有关!检查您是否没有释放两次或更多次相同的堆内存,再次关闭已经关闭的文件或管道。祝你好运

于 2010-07-21T19:34:50.580 回答