Permalink
Browse files

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>'
  • Loading branch information...
kou committed Mar 6, 2016
1 parent d77c72d commit f1eb3aea114cbd1e2622cbe9618571f3e1eec115
Showing with 12 additions and 2 deletions.
  1. +7 −2 src/error.c
  2. +5 −0 src/gc.c
View
@@ -255,17 +255,22 @@ mrb_exc_set(mrb_state *mrb, mrb_value exc)
{
if (!mrb->gc.out_of_memory && mrb->backtrace.n > 0) {
mrb_value target_exc = mrb_nil_value();
int ai;
ai = mrb_gc_arena_save(mrb);
if ((mrb->exc && !have_backtrace(mrb, mrb->exc))) {
target_exc = mrb_obj_value(mrb->exc);
}
else if (!mrb_nil_p(exc) && mrb_obj_ptr(exc) == mrb->backtrace.exc) {
target_exc = exc;
else if (!mrb_nil_p(exc) && mrb->backtrace.exc) {
target_exc = mrb_obj_value(mrb->backtrace.exc);
mrb_gc_protect(mrb, target_exc);
}
if (!mrb_nil_p(target_exc)) {
mrb_value backtrace;
backtrace = mrb_restore_backtrace(mrb);
set_backtrace(mrb, target_exc, backtrace);
}
mrb_gc_arena_restore(mrb, ai);
}
mrb->backtrace.n = 0;
View
@@ -695,8 +695,13 @@ obj_free(mrb_state *mrb, struct RBasic *obj)
#endif
case MRB_TT_OBJECT:
mrb_gc_free_iv(mrb, (struct RObject*)obj);
break;
case MRB_TT_EXCEPTION:
mrb_gc_free_iv(mrb, (struct RObject*)obj);
if ((struct RObject*)obj == mrb->backtrace.exc)
mrb->backtrace.exc = 0;
break;
case MRB_TT_CLASS:

0 comments on commit f1eb3ae

Please sign in to comment.