Bug #9859

An object with 6 instance variables causes SEGV

Added by Akira Tanaka about 1 year ago. Updated about 1 year ago.

[ruby-dev:48233]
Status:Closed
Priority:Normal
Assignee:-
ruby -v:ruby 2.2.0dev (2014-05-24 trunk 46062) [x86_64-linux] Backport:2.0.0: UNKNOWN, 2.1: UNKNOWN

Description

気がついたのですが、以下のようにすると SEGV します。

% ./miniruby -e '
class C
  def initialize
    @a = nil
    @b = nil
    @c = nil
    @d = nil
    @e = nil
    @f = nil
  end
end

GC.stress = true
C.new
'
-e:9: [BUG] Segmentation fault at 0x00000000000070
ruby 2.2.0dev (2014-05-24 trunk 46062) [x86_64-linux]

-- Control frame information -----------------------------------------------
c:0004 p:0039 s:0011 e:000009 METHOD -e:9 [FINISH]
c:0003 p:---- s:0007 e:000006 CFUNC  :new
c:0002 p:0035 s:0004 E:0008d8 EVAL   -e:14 [FINISH]
c:0001 p:0000 s:0002 E:0020e8 TOP    [FINISH]

-- Ruby level backtrace information ----------------------------------------
-e:14:in `<main>'
-e:14:in `new'
-e:9:in `initialize'

-- C level backtrace information -------------------------------------------
/home/ruby/tst1/ruby/miniruby(rb_print_backtrace+0x19) [0x7f07d0e0c3fb] vm_dump.c:685
/home/ruby/tst1/ruby/miniruby(rb_vm_bugreport+0x93) [0x7f07d0e0c4a4] vm_dump.c:824
/home/ruby/tst1/ruby/miniruby(report_bug+0x18d) [0x7f07d0c9cb4a] error.c:312
/home/ruby/tst1/ruby/miniruby(rb_bug+0xdf) [0x7f07d0c9ccc4] error.c:339
/home/ruby/tst1/ruby/miniruby(sigsegv+0x86) [0x7f07d0d7eba4] signal.c:815
/lib/x86_64-linux-gnu/libpthread.so.0 [0x7f07d0806890]
/home/ruby/tst1/ruby/miniruby(gc_marked+0x42) [0x7f07d0cbe70c] gc.c:3595
/home/ruby/tst1/ruby/miniruby(rgengc_check_relation+0x7f) [0x7f07d0cbe89b] gc.c:3620
/home/ruby/tst1/ruby/miniruby(gc_mark+0x58) [0x7f07d0cbe943] gc.c:3643
/home/ruby/tst1/ruby/miniruby(gc_mark_children+0x6ac) [0x7f07d0cbf12c] gc.c:3956
/home/ruby/tst1/ruby/miniruby(gc_mark_stacked_objects+0x44) [0x7f07d0cbf3a5] gc.c:4033
/home/ruby/tst1/ruby/miniruby(gc_marks_body+0x107) [0x7f07d0cbf6f5] gc.c:4223
/home/ruby/tst1/ruby/miniruby(gc_marks+0x54) [0x7f07d0cbfa16] gc.c:4579
/home/ruby/tst1/ruby/miniruby(garbage_collect_body+0x1fa) [0x7f07d0cc0e3e] gc.c:5101
/home/ruby/tst1/ruby/miniruby(garbage_collect+0x97) [0x7f07d0cc0fd2] gc.c:5156
/home/ruby/tst1/ruby/miniruby(garbage_collect_with_gvl+0x4b) [0x7f07d0cc105b] gc.c:5178
/home/ruby/tst1/ruby/miniruby(objspace_malloc_increase+0x105) [0x7f07d0cc341c] gc.c:6133
/home/ruby/tst1/ruby/miniruby(objspace_xrealloc+0x128) [0x7f07d0cc36c4] gc.c:6274
/home/ruby/tst1/ruby/miniruby(ruby_sized_xrealloc2+0x8a) [0x7f07d0cc3a0c] gc.c:6361
/home/ruby/tst1/ruby/miniruby(ruby_xrealloc2+0x2d) [0x7f07d0cc3a3b] gc.c:6367
/home/ruby/tst1/ruby/miniruby(rb_ivar_set+0x335) [0x7f07d0dcd4eb] variable.c:1183
/home/ruby/tst1/ruby/miniruby(vm_setivar+0x2c5) [0x7f07d0df0190] vm_insnhelper.c:574
/home/ruby/tst1/ruby/miniruby(vm_setinstancevariable+0x3c) [0x7f07d0df0203] vm_insnhelper.c:586
/home/ruby/tst1/ruby/miniruby(vm_exec_core+0x436) [0x7f07d0df560d] insns.def:146
/home/ruby/tst1/ruby/miniruby(vm_exec+0xe7) [0x7f07d0e07ab9] vm.c:1335
/home/ruby/tst1/ruby/miniruby(vm_call0_body+0x181) [0x7f07d0e005f8] vm_eval.c:175
/home/ruby/tst1/ruby/miniruby(vm_call0+0xaa) [0x7f07d0e0016b] vm_eval.c:54
/home/ruby/tst1/ruby/miniruby(rb_call0+0xae) [0x7f07d0e00c4b] vm_eval.c:333
/home/ruby/tst1/ruby/miniruby(rb_call+0x50) [0x7f07d0e01610] vm_eval.c:595
/home/ruby/tst1/ruby/miniruby(rb_funcallv+0x34) [0x7f07d0e01e9e] vm_eval.c:810
/home/ruby/tst1/ruby/miniruby(rb_obj_call_init+0x67) [0x7f07d0ca55e6] eval.c:1342
/home/ruby/tst1/ruby/miniruby(rb_class_new_instance+0x38) [0x7f07d0d06b07] object.c:1842
/home/ruby/tst1/ruby/miniruby(call_cfunc_m1+0x2f) [0x7f07d0df20a8] vm_insnhelper.c:1330
/home/ruby/tst1/ruby/miniruby(vm_call_cfunc_with_frame+0x216) [0x7f07d0df2c57] vm_insnhelper.c:1502
/home/ruby/tst1/ruby/miniruby(vm_call_cfunc+0x2b) [0x7f07d0df2d64] vm_insnhelper.c:1592
/home/ruby/tst1/ruby/miniruby(vm_call_method+0x113) [0x7f07d0df3879] vm_insnhelper.c:1786
/home/ruby/tst1/ruby/miniruby(vm_call_general+0x2b) [0x7f07d0df40ea] vm_insnhelper.c:1941
/home/ruby/tst1/ruby/miniruby(vm_exec_core+0x27cd) [0x7f07d0df79a4] insns.def:1028
/home/ruby/tst1/ruby/miniruby(vm_exec+0xe7) [0x7f07d0e07ab9] vm.c:1335
/home/ruby/tst1/ruby/miniruby(rb_iseq_eval_main+0x34) [0x7f07d0e08c02] vm.c:1599
/home/ruby/tst1/ruby/miniruby(ruby_exec_internal+0x134) [0x7f07d0ca2b9a] eval.c:252
/home/ruby/tst1/ruby/miniruby(ruby_exec_node+0x24) [0x7f07d0ca2cc3] eval.c:317
/home/ruby/tst1/ruby/miniruby(ruby_run_node+0x3e) [0x7f07d0ca2c96] eval.c:309
/home/ruby/tst1/ruby/miniruby(main+0x71) [0x7f07d0c57596] main.c:36

-- Other runtime information -----------------------------------------------

* Loaded script: -e

* Loaded features:

    0 enumerator.so

* Process memory map:

7f07cf096000-7f07cf23e000 r--s 00000000 08:02 2884067                    /lib/x86_64-linux-gnu/libc-2.18.so
7f07cf23e000-7f07cf77f000 r--s 00000000 08:02 12981089                   /home/ruby/tst1/ruby/miniruby
7f07cf77f000-7f07cf795000 r-xp 00000000 08:02 2884113                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7f07cf795000-7f07cf994000 ---p 00016000 08:02 2884113                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7f07cf994000-7f07cf995000 rw-p 00015000 08:02 2884113                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7f07cf995000-7f07cfa96000 rw-p 00000000 00:00 0 
7f07cfa96000-7f07cfc36000 r-xp 00000000 08:02 2884067                    /lib/x86_64-linux-gnu/libc-2.18.so
7f07cfc36000-7f07cfe36000 ---p 001a0000 08:02 2884067                    /lib/x86_64-linux-gnu/libc-2.18.so
7f07cfe36000-7f07cfe3a000 r--p 001a0000 08:02 2884067                    /lib/x86_64-linux-gnu/libc-2.18.so
7f07cfe3a000-7f07cfe3c000 rw-p 001a4000 08:02 2884067                    /lib/x86_64-linux-gnu/libc-2.18.so
7f07cfe3c000-7f07cfe40000 rw-p 00000000 00:00 0 
7f07cfe40000-7f07cff41000 r-xp 00000000 08:02 2884071                    /lib/x86_64-linux-gnu/libm-2.18.so
7f07cff41000-7f07d0141000 ---p 00101000 08:02 2884071                    /lib/x86_64-linux-gnu/libm-2.18.so
7f07d0141000-7f07d0142000 r--p 00101000 08:02 2884071                    /lib/x86_64-linux-gnu/libm-2.18.so
7f07d0142000-7f07d0143000 rw-p 00102000 08:02 2884071                    /lib/x86_64-linux-gnu/libm-2.18.so
7f07d0143000-7f07d014b000 r-xp 00000000 08:02 2884069                    /lib/x86_64-linux-gnu/libcrypt-2.18.so
7f07d014b000-7f07d034a000 ---p 00008000 08:02 2884069                    /lib/x86_64-linux-gnu/libcrypt-2.18.so
7f07d034a000-7f07d034b000 r--p 00007000 08:02 2884069                    /lib/x86_64-linux-gnu/libcrypt-2.18.so
7f07d034b000-7f07d034c000 rw-p 00008000 08:02 2884069                    /lib/x86_64-linux-gnu/libcrypt-2.18.so
7f07d034c000-7f07d037a000 rw-p 00000000 00:00 0 
7f07d037a000-7f07d037d000 r-xp 00000000 08:02 2884070                    /lib/x86_64-linux-gnu/libdl-2.18.so
7f07d037d000-7f07d057c000 ---p 00003000 08:02 2884070                    /lib/x86_64-linux-gnu/libdl-2.18.so
7f07d057c000-7f07d057d000 r--p 00002000 08:02 2884070                    /lib/x86_64-linux-gnu/libdl-2.18.so
7f07d057d000-7f07d057e000 rw-p 00003000 08:02 2884070                    /lib/x86_64-linux-gnu/libdl-2.18.so
7f07d057e000-7f07d05f5000 r-xp 00000000 08:02 24906866                   /usr/lib/x86_64-linux-gnu/libgmp.so.10.2.0
7f07d05f5000-7f07d07f5000 ---p 00077000 08:02 24906866                   /usr/lib/x86_64-linux-gnu/libgmp.so.10.2.0
7f07d07f5000-7f07d07f6000 r--p 00077000 08:02 24906866                   /usr/lib/x86_64-linux-gnu/libgmp.so.10.2.0
7f07d07f6000-7f07d07f7000 rw-p 00078000 08:02 24906866                   /usr/lib/x86_64-linux-gnu/libgmp.so.10.2.0
7f07d07f7000-7f07d080f000 r-xp 00000000 08:02 2883744                    /lib/x86_64-linux-gnu/libpthread-2.18.so
7f07d080f000-7f07d0a0e000 ---p 00018000 08:02 2883744                    /lib/x86_64-linux-gnu/libpthread-2.18.so
7f07d0a0e000-7f07d0a0f000 r--p 00017000 08:02 2883744                    /lib/x86_64-linux-gnu/libpthread-2.18.so
7f07d0a0f000-7f07d0a10000 rw-p 00018000 08:02 2883744                    /lib/x86_64-linux-gnu/libpthread-2.18.so
7f07d0a10000-7f07d0a14000 rw-p 00000000 00:00 0 
7f07d0a14000-7f07d0a34000 r-xp 00000000 08:02 2883965                    /lib/x86_64-linux-gnu/ld-2.18.so
7f07d0a43000-7f07d0ae7000 r--s 00000000 08:02 24905885                   /usr/lib/debug/lib/x86_64-linux-gnu/libpthread-2.18.so
7f07d0ae7000-7f07d0b09000 r--s 00000000 08:02 2883744                    /lib/x86_64-linux-gnu/libpthread-2.18.so
7f07d0b09000-7f07d0c11000 r--p 00000000 08:02 24911940                   /usr/lib/locale/locale-archive
7f07d0c11000-7f07d0c16000 rw-p 00000000 00:00 0 
7f07d0c2c000-7f07d0c2d000 rw-p 00000000 00:00 0 
7f07d0c2d000-7f07d0c2e000 ---p 00000000 00:00 0 
7f07d0c2e000-7f07d0c33000 rw-p 00000000 00:00 0                          
7f07d0c33000-7f07d0c34000 r--p 0001f000 08:02 2883965                    /lib/x86_64-linux-gnu/ld-2.18.so
7f07d0c34000-7f07d0c35000 rw-p 00020000 08:02 2883965                    /lib/x86_64-linux-gnu/ld-2.18.so
7f07d0c35000-7f07d0c36000 rw-p 00000000 00:00 0 
7f07d0c36000-7f07d0ed8000 r-xp 00000000 08:02 12981089                   /home/ruby/tst1/ruby/miniruby
7f07d10d8000-7f07d10de000 rw-p 002a2000 08:02 12981089                   /home/ruby/tst1/ruby/miniruby
7f07d10de000-7f07d1105000 rw-p 00000000 00:00 0 
7f07d2e0f000-7f07d2f9f000 rw-p 00000000 00:00 0                          [heap]
7fff4135c000-7fff4137d000 rw-p 00000000 00:00 0 
7fff413fe000-7fff41400000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]


[NOTE]
You may have encountered a bug in the Ruby interpreter or extension libraries.
Bug reports are welcome.
For details: http://www.ruby-lang.org/bugreport.html

Related issues

Related to Ruby trunk - Feature #9761: TRY_WITH_GC with ruby_gc_stress Closed 04/20/2014

Associated revisions

Revision 46399
Added by Koichi Sasada about 1 year ago

  • gc.c: invoke GC before memory allocation (xmalloc/xrealloc) when GC.stress = true. [Bug #9859]
  • test/ruby/test_gc.rb: add a test.

Revision 46399
Added by Koichi Sasada about 1 year ago

  • gc.c: invoke GC before memory allocation (xmalloc/xrealloc) when GC.stress = true. [Bug #9859]
  • test/ruby/test_gc.rb: add a test.

History

#1 Updated by Koichi Sasada about 1 year ago

(2014/05/24 4:33), akr@fsij.org wrote:

気がついたのですが、以下のようにすると SEGV します。

ちょっと追ってみたのですが、

variable.c の

REALLOC_N(ROBJECT(obj)->as.heap.ivptr, VALUE, newsize);

xrealloc() が成功後、GC 発生して、mark 関数(mark_children
T_OBJECT)において、xrealloc によって解放された古いバッファを参照してい
るため、であるようです。

どっかのタイミングで xrealloc でも GC.stress による強制 GC がされるよう
になったと思いますが、xrealloc が成功後、こんなふうに GC が走ると死んで
しまうので、xrealloc 成功時での GC.stress による強制 GC はダメなんじゃな
いでしょうか。

(元の議論の場所を思い出せない)

--
// SASADA Koichi at atdot dot net

#2 Updated by Nobuyoshi Nakada about 1 year ago

  • Related to Feature #9761: TRY_WITH_GC with ruby_gc_stress added

#3 Updated by Nobuyoshi Nakada about 1 year ago

r45653で強制GCが走るようになった後、r45656で

  • gc.c (objspace_malloc_increase): don't cause GC by malloc_increase when memop type is MEMOP_TYPE_REALLOC.

と再変更されたものの、まだMEMOP_TYPE_REALLOCでも実行するままのようです。

    if (type != MEMOP_TYPE_FREE &&
       ruby_gc_stress && !ruby_disable_gc_stress &&
       ruby_native_thread_p()) {
       garbage_collect_with_gvl(objspace, gc_stress_full_mark_after_malloc_p(), TRUE, GPR_FLAG_MALLOC);
    }

#4 Updated by Nobuyoshi Nakada about 1 year ago

MEMOP_TYPE_REALLOCでは実行しないようにするか、REALLOC_Nにポインタへの参照を渡してxreallocの中で書き換えさせるとか、でしょうか。
xreallocを直に使われると後者ではどうしようもないですが。

#5 Updated by Akira Tanaka about 1 year ago

Koichi Sasada wrote:

xrealloc() が成功後、GC 発生して、mark 関数(mark_children
T_OBJECT)において、xrealloc によって解放された古いバッファを参照してい
るため、であるようです。

どっかのタイミングで xrealloc でも GC.stress による強制 GC がされるよう
になったと思いますが、xrealloc が成功後、こんなふうに GC が走ると死んで
しまうので、xrealloc 成功時での GC.stress による強制 GC はダメなんじゃな
いでしょうか。

昔、私が 1.8 で GC.stress を実装したときは、realloc の前で GC をやっていました。
そうしておけば、そのような問題は発生しないと思います。

どんな経過があって現在の状況になったのはたどっていませんが。

#6 Updated by Nobuyoshi Nakada about 1 year ago

経緯は調べてませんが、実際のreallocによるnew_sizeの補正が入らなくなりますね。

diff --git i/gc.c w/gc.c
index 6c9547e..f18d2d0 100644
--- i/gc.c
+++ w/gc.c
@@ -6263,16 +6263,15 @@ objspace_xrealloc(rb_objspace_t *objspace, void *ptr, size_t new_size, size_t ol
 #endif

     old_size = objspace_malloc_size(objspace, ptr, old_size);
+    objspace_malloc_increase(objspace, 0, new_size, old_size, MEMOP_TYPE_REALLOC);
     TRY_WITH_GC(mem = realloc(ptr, new_size));
-    new_size = objspace_malloc_size(objspace, mem, new_size);

 #if CALC_EXACT_MALLOC_SIZE
+    new_size = objspace_malloc_size(objspace, mem, new_size);
     ((size_t *)mem)[0] = new_size;
     mem = (size_t *)mem + 1;
 #endif

-    objspace_malloc_increase(objspace, mem, new_size, old_size, MEMOP_TYPE_REALLOC);
-
     return mem;
 }

diff --git i/test/ruby/test_gc.rb w/test/ruby/test_gc.rb
index 3d0bca6..78a6826 100644
--- i/test/ruby/test_gc.rb
+++ w/test/ruby/test_gc.rb
@@ -311,4 +311,23 @@ class TestGc < Test::Unit::TestCase
   def test_verify_internal_consistency
     assert_nil(GC.verify_internal_consistency)
   end
+
+  def test_gc_after_realloc
+    bug9859 = ' [Bug #9859]'
+    assert_ruby_status([], <<-'end;', bug9859)#    do
+      class C
+        def initialize
+          @a = nil
+          @b = nil
+          @c = nil
+          @d = nil
+          @e = nil
+          @f = nil
+        end
+      end
+
+      GC.stress = true
+      C.new
+    end;
+  end
 end

#7 Updated by Akira Tanaka about 1 year ago

補正が入らなくなるというのがどのくらい問題があるのかわかっていませんが、
SEGV するよりはずいぶんとマシなんじゃないですかねぇ。

#8 Updated by Koichi Sasada about 1 year ago

  • Status changed from Open to Closed
  • % Done changed from 0 to 100

Applied in changeset r46399.


  • gc.c: invoke GC before memory allocation (xmalloc/xrealloc) when GC.stress = true. [Bug #9859]
  • test/ruby/test_gc.rb: add a test.

Also available in: Atom PDF