From bd6e6c59cb823cc30d693683afa831ea15d8863a Mon Sep 17 00:00:00 2001 From: Kouhei Sutou Date: Mon, 17 Aug 2015 14:08:52 +0900 Subject: [PATCH] Mark backtrace referenced by exception The following code crashes without this change: def a [1].each do [2].each do [3].each do raise "XXX" end end end end begin a rescue => exception GC.start exception.backtrace end GDB backtrace: Program received signal SIGSEGV, Segmentation fault. strlen () at ../sysdeps/x86_64/strlen.S:106 106 ../sysdeps/x86_64/strlen.S: No such file or directory. (gdb) bt #0 strlen () at ../sysdeps/x86_64/strlen.S:106 #1 0x00000000004252cd in mrb_str_new_cstr (mrb=0x69f010, p=0x101 ) at mruby/src/string.c:290 #2 0x00000000004183fe in get_backtrace_i (mrb=0x69f010, loc=0x7fffffffd940, data=0x6a7410) at mruby/src/backtrace.c:72 #3 0x0000000000418793 in output_backtrace (mrb=0x69f010, ciidx=8, pc0=0x71940c, func=0x4183af , data=0x6a7410) at mruby/src/backtrace.c:140 #4 0x0000000000418862 in exc_output_backtrace (mrb=0x69f010, exc=0x6a5be0, func=0x4183af , stream=0x6a7410) at mruby/src/backtrace.c:157 #5 0x000000000041894c in mrb_exc_backtrace (mrb=0x69f010, self=...) at mruby/src/backtrace.c:199 #6 0x000000000040dbaf in mrb_context_run (mrb=0x69f010, proc=0x6a61b0, self=..., stack_keep=0) at mruby/src/vm.c:1126 #7 0x00000000004131d8 in mrb_toplevel_run_keep (mrb=0x69f010, proc=0x6a61b0, stack_keep=0) at mruby/src/vm.c:2422 #8 0x000000000043a46c in load_exec (mrb=0x69f010, p=0x6f6450, c=0x6c9320) at mruby/mrbgems/mruby-compiler/core/parse.y:5619 #9 0x000000000043a4e2 in mrb_load_file_cxt (mrb=0x69f010, f=0x6f61f0, c=0x6c9320) at mruby/mrbgems/mruby-compiler/core/parse.y:5628 #10 0x0000000000402466 in main (argc=2, argv=0x7fffffffe438) at mruby/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c:222 --- src/gc.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/gc.c b/src/gc.c index 8bd8243f10..e074cc9767 100644 --- a/src/gc.c +++ b/src/gc.c @@ -514,10 +514,27 @@ gc_mark_children(mrb_state *mrb, struct RBasic *obj) case MRB_TT_OBJECT: case MRB_TT_DATA: - case MRB_TT_EXCEPTION: mrb_gc_mark_iv(mrb, (struct RObject*)obj); break; + case MRB_TT_EXCEPTION: + { + mrb_int i, ciidx; + + mrb_gc_mark_iv(mrb, (struct RObject*)obj); + + ciidx = mrb_fixnum(mrb_obj_iv_get(mrb, (struct RObject*)obj, + mrb_intern_lit(mrb, "ciidx"))); + for (i = 0; i <= ciidx; i++) { + mrb_callinfo *ci = &mrb->c->cibase[i]; + if (!ci->proc) { + continue; + } + mrb_gc_mark(mrb, (struct RBasic*)ci->proc); + } + } + break; + case MRB_TT_PROC: { struct RProc *p = (struct RProc*)obj;