From: Nikolai Lugovoi Date: 2009-09-04T07:19:00+09:00 Subject: Odd random segfaults in 1.9.2dev with gem method Got some segfault errors when trying to run rake test for rails. Minimal code example to reproduce is: ruby -e 'gem "rake"' the odd thing is that these segfaults are not 100% reproducible, sometimes it works as expected: -----8<---------- $ ruby -e 'gem "rake"' :187:in `push_gem_version_on_load_path': Could not find RubyGem rake (>= 0) (Gem::LoadError)         from /home/nlugovoi/lib/ruby/1.9.1/rubygems/defaults.rb:0:in `rescue in default_exec_format'         from -e:1:in `
' -----8<---------- But sometimes it just fails: -----8<---------- $ ruby -e 'gem "rake"' /home/nlugovoi/lib/ruby/1.9.1/rubygems.rb:1093: [BUG] Segmentation fault ruby 1.9.2dev (2009-09-04 trunk 24743) [i686-linux] -- control frame ---------- c:0012 p:---- s:0043 b:0043 l:000042 d:000042 CFUNC  :require c:0011 p:0209 s:0039 b:0039 l:000038 d:000038 TOP /home/nlugovoi/lib/ruby/1.9.1/rubygems.rb:1093 c:0010 p:---- s:0036 b:0036 l:000035 d:000035 FINISH c:0009 p:---- s:0034 b:0034 l:000033 d:000033 CFUNC  :require c:0008 p:0092 s:0030 b:0030 l:000029 d:000029 METHOD :159 c:0007 p:0017 s:0027 b:0027 l:000026 d:000026 METHOD :279 c:0006 p:---- s:0023 b:0023 l:000022 d:000022 FINISH c:0005 p:0043 s:0021 b:0020 l:000019 d:000019 METHOD :187 Segmentation fault -----8<---------- From gdb I get: -----8<---------- #0  0x0813a387 in vm_backtrace_push (arg=0xbfffa0ec, file=0, line_no=0, name=0) at vm.c:755 #1  0x0813a2db in vm_backtrace_each (th=0x81faa98, lev=-2, iter=0x813a363 , arg=0xbfffa0ec) at vm.c:733 #2  0x0813a44c in vm_backtrace (th=0x81faa98, lev=-1) at vm.c:768 #3  0x08138ac7 in rb_make_backtrace () at vm_eval.c:1426 #4  0x0805b8ac in rb_longjmp (tag=6, mesg=140818900) at eval.c:363 #5  0x0805bb5e in rb_exc_raise (mesg=140818900) at eval.c:419 #6  0x0816d319 in rb_raise (exc=136482940, fmt=0x81a3676 "no such file to load -- %s") at error.c:1132 #7  0x0816f580 in load_failed (fname=140824860) at load.c:532 754         bt = rb_enc_sprintf(rb_enc_compatible(file, name), "%s:%d:in `%s'", 755                             RSTRING_PTR(file), line_no, RSTRING_PTR(name)); (gdb) up #1  0x0813a2db in vm_backtrace_each (th=0x81faa98, lev=-2, iter=0x813a363 , arg=0xbfffa0ec) at vm.c:733 733                     if ((*iter)(arg, file, line_no, iseq->name)) break; (gdb) l 728                 if (cfp->pc != 0) { 729                     rb_iseq_t *iseq = cfp->iseq; 730 731                     line_no = rb_vm_get_sourceline(cfp); 732                     file = iseq->filename; 733                     if ((*iter)(arg, file, line_no, iseq->name)) break; 734                 } -----8<---------- My theory is that when method Kernel#gem, originally defined in gem_prelude,  is redefined/discarded in rubygems.rb, then original iseq for method becomes orphaned and is freed by garbage collector. But it is still referenced from control frame, so segfault. I tried quick&dirty patch to explicitly mark iseq objects, not sure if it is correct way: -----8<---------- --- a/vm.c +++ b/vm.c @@ -1415,7 +1415,21 @@ static int vm_mark_each_thread_func(st_data_t key, st_data_t value, st_data_t dummy) { VALUE thval = (VALUE)key; + rb_thread_t *th; + rb_control_frame_t *cfp; + + GetThreadPtr(thval, th); + + cfp = th->cfp; + while (!RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, cfp)) { + if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) { + rb_gc_mark(cfp->iseq->self); + } + cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); + } + rb_gc_mark(thval); + return ST_CONTINUE; } -----8<---------- and that seemed to eliminate such segfaults Any other explanations or fixes?