Commit f1eb3aea authored by Kouhei Sutou's avatar Kouhei Sutou

Fix segmentation fault by backtrace and GC

GitHub: fix #3122

It reverts #3126. #3126 fixes the segmentation fault but generates
broken backtrace.

This change fixes the segmentation fault and generates correct
backtrace. The strategy of this change is "generating backtrace while
irep is alive".

/tmp/test.rb:
    def gen
      e0 = nil
      begin
        1.times {
          raise 'foobar'
        }
      rescue => e
        e0 = e
      end
      e0
    end

    e = gen
    GC.start
    gen
    GC.start

    puts e.backtrace.join("\n")

Run:

    % bin/mruby /tmp/test.rb
    /tmp/test.rb:5:in Object.gen
    /home/kou/work/ruby/mruby.kou/mrblib/numeric.rb:77:in Integral#times
    /tmp/test.rb:4:in Object.gen
    /tmp/test.rb:13

FYI:

    % ruby -v /tmp/test.rb
    ruby 2.3.0p0 (2015-12-25) [x86_64-linux-gnu]
    /tmp/test.rb:5:in `block in gen'
    /tmp/test.rb:4:in `times'
    /tmp/test.rb:4:in `gen'
    /tmp/test.rb:13:in `<main>'
parent d77c72da
...@@ -255,17 +255,22 @@ mrb_exc_set(mrb_state *mrb, mrb_value exc) ...@@ -255,17 +255,22 @@ mrb_exc_set(mrb_state *mrb, mrb_value exc)
{ {
if (!mrb->gc.out_of_memory && mrb->backtrace.n > 0) { if (!mrb->gc.out_of_memory && mrb->backtrace.n > 0) {
mrb_value target_exc = mrb_nil_value(); mrb_value target_exc = mrb_nil_value();
int ai;
ai = mrb_gc_arena_save(mrb);
if ((mrb->exc && !have_backtrace(mrb, mrb->exc))) { if ((mrb->exc && !have_backtrace(mrb, mrb->exc))) {
target_exc = mrb_obj_value(mrb->exc); target_exc = mrb_obj_value(mrb->exc);
} }
else if (!mrb_nil_p(exc) && mrb_obj_ptr(exc) == mrb->backtrace.exc) { else if (!mrb_nil_p(exc) && mrb->backtrace.exc) {
target_exc = exc; target_exc = mrb_obj_value(mrb->backtrace.exc);
mrb_gc_protect(mrb, target_exc);
} }
if (!mrb_nil_p(target_exc)) { if (!mrb_nil_p(target_exc)) {
mrb_value backtrace; mrb_value backtrace;
backtrace = mrb_restore_backtrace(mrb); backtrace = mrb_restore_backtrace(mrb);
set_backtrace(mrb, target_exc, backtrace); set_backtrace(mrb, target_exc, backtrace);
} }
mrb_gc_arena_restore(mrb, ai);
} }
mrb->backtrace.n = 0; mrb->backtrace.n = 0;
......
...@@ -695,8 +695,13 @@ obj_free(mrb_state *mrb, struct RBasic *obj) ...@@ -695,8 +695,13 @@ obj_free(mrb_state *mrb, struct RBasic *obj)
#endif #endif
case MRB_TT_OBJECT: case MRB_TT_OBJECT:
mrb_gc_free_iv(mrb, (struct RObject*)obj);
break;
case MRB_TT_EXCEPTION: case MRB_TT_EXCEPTION:
mrb_gc_free_iv(mrb, (struct RObject*)obj); mrb_gc_free_iv(mrb, (struct RObject*)obj);
if ((struct RObject*)obj == mrb->backtrace.exc)
mrb->backtrace.exc = 0;
break; break;
case MRB_TT_CLASS: case MRB_TT_CLASS:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment