Issue #10768 has been updated by Koichi Sasada.


Thank you for confirmation.

> Would you like me to commit it to trunk?

Yes, please!

----------------------------------------
Bug #10768: segfault during ruby_vm_destruct() in cont_free()
https://bugs.ruby-lang.org/issues/10768#change-51308

* 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=<optimized out>, line=<optimized out>, 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=<optimized out>, info=<optimized out>, ctx=<optimized out>) at signal.c:812
#4  <signal handler called>
#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=<optimized out>) 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 <cont_free+184>
   0x00007ff4f274eead <+13>:	mov    0x60(%rdi),%rdi
   0x00007ff4f274eeb1 <+17>:	test   %rdi,%rdi
   0x00007ff4f274eeb4 <+20>:	je     0x7ff4f274eec3 <cont_free+35>
   0x00007ff4f274eeb6 <+22>:	callq  0x7ff4f261cef0 <ruby_xfree>
   0x00007ff4f274eebb <+27>:	movq   $0x0,0x60(%rbx)
   0x00007ff4f274eec3 <+35>:	mov    0x3100de(%rip),%rax        # 0x7ff4f2a5efa8
   0x00007ff4f274eeca <+42>:	mov    (%rax),%rdi
   0x00007ff4f274eecd <+45>:	callq  0x7ff4f25fcc80 <fflush / plt>
   0x00007ff4f274eed2 <+50>:	mov    (%rbx),%eax
   0x00007ff4f274eed4 <+52>:	test   %eax,%eax
   0x00007ff4f274eed6 <+54>:	je     0x7ff4f274ef30 <cont_free+144>
   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 <cont_free+108>
   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/