diff options
| author | Kouhei Sutou <[email protected]> | 2016-03-06 11:58:54 +0900 |
|---|---|---|
| committer | Kouhei Sutou <[email protected]> | 2016-03-06 11:58:54 +0900 |
| commit | f1eb3aea114cbd1e2622cbe9618571f3e1eec115 (patch) | |
| tree | 1eb3d36738e3c0fe87366347ab6004d01d22abf7 /src/error.c | |
| parent | d77c72dac5b46dacc8332bca73a8398ae2cf9a78 (diff) | |
| download | mruby-f1eb3aea114cbd1e2622cbe9618571f3e1eec115.tar.gz mruby-f1eb3aea114cbd1e2622cbe9618571f3e1eec115.zip | |
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>'
Diffstat (limited to 'src/error.c')
| -rw-r--r-- | src/error.c | 9 |
1 files changed, 7 insertions, 2 deletions
diff --git a/src/error.c b/src/error.c index 14e4ab4d3..13032b136 100644 --- a/src/error.c +++ b/src/error.c @@ -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; |
