From: ruby@...1.net Date: 2015-01-26T20:45:32+00:00 Subject: [ruby-core:67821] [ruby-trunk - Bug #10768] segfault during ruby_vm_destruct() in cont_free() Issue #10768 has been updated by Aman Gupta. After some investigation, it appears the background threads in our app are unrelated to this segfault. ruby_vm_destruct will call thread_free, which sets ruby_current_thread to NULL (https://github.com/ruby/ruby/blob/v2_1_4/vm.c#L2117-L2118). This means any attempt to access GET_THREAD from objspace_free will cause a segfault. We propose the following patch: https://github.com/github/ruby/commit/1ae74499395d ---------------------------------------- Bug #10768: segfault during ruby_vm_destruct() in cont_free() https://bugs.ruby-lang.org/issues/10768#change-51229 * Author: Aman Gupta * Status: Open * Priority: Normal * Assignee: * ruby -v: 2.1.5 * Backport: 2.0.0: UNKNOWN, 2.1: UNKNOWN, 2.2: UNKNOWN ---------------------------------------- ~~~ (gdb) where #0 rb_vm_bugreport () at vm_dump.c:738 #1 0x00007ff4f279de2c in report_bug (file=, line=, fmt=0x7ff4f27cfce7 "Segmentation fault at %p", args=0x7ff4f4afd998) at error.c:312 #2 0x00007ff4f279f747 in rb_bug (fmt=0x7ff4f27cfce7 "Segmentation fault at %p") at error.c:339 #3 0x00007ff4f26c0057 in sigsegv (sig=, info=, ctx=) at signal.c:812 #4 #5 0x00007ff4f274eee6 in cont_free (ptr=0x7ff4f96fd200) at cont.c:244 #6 0x00007ff4f261af6a in obj_free (obj=140690513703000, objspace=0x7ff4f4aee000) at gc.c:1619 #7 gc_page_sweep (sweep_page=0x7ff50c621100, heap=0x7ff4f4aee010, objspace=0x7ff4f4aee000) at gc.c:2787 #8 gc_heap_lazy_sweep (objspace=0x7ff4f4aee000, heap=0x7ff4f4aee010) at gc.c:3058 #9 0x00007ff4f261b4e3 in gc_heap_rest_sweep (heap=0x7ff4f4aee010, objspace=0x7ff4f4aee000) at gc.c:3083 #10 gc_rest_sweep (objspace=0x7ff4f4aee000) at gc.c:3093 #11 rb_objspace_free (objspace=0x7ff4f4aee000) at gc.c:923 #12 0x00007ff4f273be71 in ruby_vm_destruct (vm=0x7ff4f4af4000) at vm.c:1840 #13 0x00007ff4f26018d7 in ruby_cleanup (ex=0) at eval.c:236 #14 0x00007ff4f2601c0d in ruby_run_node (n=) at eval.c:310 #15 0x00007ff4f25fe35b in main (argc=12, argv=0x7fff35737458) at main.c:36 ~~~ ~~~ (gdb) frame 5 #5 0x00007ff4f274eee6 in cont_free (ptr=0x7ff4f96fd200) at cont.c:244 244 if (GET_THREAD()->fiber != cont->self) { ~~~ ~~~ (gdb) disas Dump of assembler code for function cont_free: 0x00007ff4f274eea0 <+0>: test %rdi,%rdi 0x00007ff4f274eea3 <+3>: push %rbx 0x00007ff4f274eea4 <+4>: mov %rdi,%rbx 0x00007ff4f274eea7 <+7>: je 0x7ff4f274ef58 0x00007ff4f274eead <+13>: mov 0x60(%rdi),%rdi 0x00007ff4f274eeb1 <+17>: test %rdi,%rdi 0x00007ff4f274eeb4 <+20>: je 0x7ff4f274eec3 0x00007ff4f274eeb6 <+22>: callq 0x7ff4f261cef0 0x00007ff4f274eebb <+27>: movq $0x0,0x60(%rbx) 0x00007ff4f274eec3 <+35>: mov 0x3100de(%rip),%rax # 0x7ff4f2a5efa8 0x00007ff4f274eeca <+42>: mov (%rax),%rdi 0x00007ff4f274eecd <+45>: callq 0x7ff4f25fcc80 0x00007ff4f274eed2 <+50>: mov (%rbx),%eax 0x00007ff4f274eed4 <+52>: test %eax,%eax 0x00007ff4f274eed6 <+54>: je 0x7ff4f274ef30 0x00007ff4f274eed8 <+56>: mov 0x30fec1(%rip),%rdx # 0x7ff4f2a5eda0 0x00007ff4f274eedf <+63>: mov 0x8(%rbx),%rcx 0x00007ff4f274eee3 <+67>: mov (%rdx),%rdx => 0x00007ff4f274eee6 <+70>: cmp %rcx,0x2f0(%rdx) 0x00007ff4f274eeed <+77>: je 0x7ff4f274ef0c 0x00007ff4f274eeef <+79>: mov 0x548(%rbx),%rdi 0x00007ff4f274eef6 <+86>: test %rdi,%rdi (gdb) info registers rax 0x1 1 rbx 0x7ff4f96fd200 140690133602816 rcx 0x7ff51017b058 140690513703000 rdx 0x0 0 ~~~ It appears GET_THREAD() is returning a NULL pointer. Does the following patch make sense? ~~~ diff diff --git a/cont.c b/cont.c index 78ae089..a94a408 100644 --- a/cont.c +++ b/cont.c @@ -236,8 +236,9 @@ cont_free(void *ptr) else { /* fiber */ rb_fiber_t *fib = (rb_fiber_t*)cont; + rb_thread_t *th = GET_THREAD(); #ifdef _WIN32 - if (GET_THREAD()->fiber != fib && cont->type != ROOT_FIBER_CONTEXT) { + if (th && th->fiber != fib && cont->type != ROOT_FIBER_CONTEXT) { /* don't delete root fiber handle */ rb_fiber_t *fib = (rb_fiber_t*)cont; if (fib->fib_handle) { @@ -245,7 +246,7 @@ cont_free(void *ptr) } } #else /* not WIN32 */ - if (GET_THREAD()->fiber != fib) { + if (th && th->fiber != fib) { rb_fiber_t *fib = (rb_fiber_t*)cont; if (fib->ss_sp) { if (cont->type == ROOT_FIBER_CONTEXT) { ~~~ -- https://bugs.ruby-lang.org/