[#3419] Valgrind analysis of [BUG] unknown node type 0 — Andrew Walrond <andrew@...>

Hello list,

19 messages 2004/09/17
[#3422] Re: Valgrind analysis of [BUG] unknown node type 0 — ts <decoux@...> 2004/09/17

>>>>> "A" == Andrew Walrond <andrew@walrond.org> writes:

[#3423] Re: Valgrind analysis of [BUG] unknown node type 0 — Andrew Walrond <andrew@...> 2004/09/17

On Friday 17 Sep 2004 12:01, ts wrote:

[#3424] Re: Valgrind analysis of [BUG] unknown node type 0 — ts <decoux@...> 2004/09/17

>>>>> "A" == Andrew Walrond <andrew@walrond.org> writes:

[#3425] Re: Valgrind analysis of [BUG] unknown node type 0 — Andrew Walrond <andrew@...> 2004/09/17

On Friday 17 Sep 2004 12:37, ts wrote:

[#3426] Re: Valgrind analysis of [BUG] unknown node type 0 — ts <decoux@...> 2004/09/17

>>>>> "A" == Andrew Walrond <andrew@walrond.org> writes:

[#3428] Re: Valgrind analysis of [BUG] unknown node type 0 — Andrew Walrond <andrew@...> 2004/09/17

On Friday 17 Sep 2004 13:05, ts wrote:

[#3429] Re: Valgrind analysis of [BUG] unknown node type 0 — ts <decoux@...> 2004/09/17

>>>>> "A" == Andrew Walrond <andrew@walrond.org> writes:

Re: [PATCH] dir.c --- Dir.chdir error handling

From: ts <decoux@...>
Date: 2004-09-16 09:54:37 UTC
List: ruby-core #3418
>>>>> "Y" == Yukihiro Matsumoto <matz@ruby-lang.org> writes:

Y> Can you show us both?

 Well, this is with the old 1.8.0 and with the example that I've given
 previously (Thread.new &thread_block).

 It's with gdb

svg% gdb ruby
[...]
(gdb) b rb_eval
Breakpoint 1 at 0x80555e0: file eval.c, line 2430.
(gdb) r b.rb

Breakpoint 1, rb_eval (self=1074436704, n=0x0) at eval.c:2430
2430        NODE * volatile node = n;
(gdb) p heaps
$1 = (struct RVALUE **) 0x80e6898
(gdb) p heaps[0]
$2 = (struct RVALUE *) 0x4007a008
(gdb) dis 1
(gdb) c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
0x080a0ab6 in st_foreach (table=0x4, func=0x8069474 <mark_entry>, arg=0)
    at st.c:492
492         for(i = 0; i < table->num_bins; i++) {
(gdb) p heaps
$3 = (struct RVALUE **) 0x80e6898
(gdb) p heaps[0]
$4 = (struct RVALUE *) 0x4007a048
(gdb) 

 It was able to modify heaps[0], this is why it crash. we just need to
 find where

Breakpoint 1, rb_eval (self=1074436704, n=0x0) at eval.c:2430
2430        NODE * volatile node = n;
(gdb) p heaps[0]
$5 = (struct RVALUE *) 0x4007a008
(gdb) watch heaps[0]
Hardware watchpoint 2: heaps[0]
(gdb) dis 1
(gdb) c
Continuing.
Hardware watchpoint 2: heaps[0]

Old value = (struct RVALUE *) 0x4007a008
New value = (struct RVALUE *) 0x4007a048
rb_gc_mark (ptr=135162008) at gc.c:630
630         CHECK_STACK(ret);
(gdb) l
625         if (rb_special_const_p(ptr)) return; /* special const not marked */
626         if (obj->as.basic.flags == 0) return;       /* free cell */
627         if (obj->as.basic.flags & FL_MARK) return;  /* already marked */ 
628         obj->as.basic.flags |= FL_MARK;
629
630         CHECK_STACK(ret);
631         if (ret) {
632             if (!mark_stack_overflow) {
633                 if (mark_stack_ptr - mark_stack < MARK_STACK_MAX) {
634                     *mark_stack_ptr = ptr;
(gdb) 

 This is the line 628 which modify heaps[0]

(gdb) bt
#0  rb_gc_mark (ptr=135162008) at gc.c:630
#1  0x080693ee in mark_locations_array (x=0xbfff43d0, n=0) at gc.c:556
#2  0x0806a191 in rb_gc_mark_frame (frame=0x845ed98) at gc.c:1160
#3  0x080611a2 in thread_mark (th=0x816fea8) at eval.c:8087

[...]

(gdb) printf "%d\n", heaps
135162008
(gdb) info reg ebp
ebp            0xbfff43a8       0xbfff43a8
(gdb) 

 It call rb_gc_mark() with heaps and it came from mark_locations_array()
 (compare the value of frame->argv (0xbfff43d0) with %ebp : it's important)

 When it call mark_locations_array(), in reality frame->argv will be at
 %ebp - 24 

 if you make the test is_pointer_to_heap(heaps) you'll see that it give
 false, but it was able to call rb_gc_mark(heaps)

 Now to see the problem, you must look at the assembler of
 mark_locations_array() (there is only the relevant part) to
 understand how it can call rb_gc_mark() with heaps

 ------------------------------------------------------------ 
mark_locations_array:

#  it store frame->argv in %edi

        movl    8(%ebp), %edi

# it store frame->argv[0] in %ecx, and now it will make the test with %ecx

        movl    (%edi), %ecx

# is_pointer_to_heap() is inlined
# it move heaps in %esi, then in (%ebp - 24) but this is the same
# address than frame->argv

        movl    heaps, %esi
        movl    heaps_limits, %eax
        movl    %esi, -24(%ebp)
        movl    %eax, -16(%ebp)

# it make the test and find that the value in %ecx is a valid value
# and it call rb_gc_mark()

.L166:
        subl    $12, %esp

# it retrieve the content of the address stored in %edi, and push it
# on the stack, but this content was modified, and in reality it push
# heaps on the stack

        pushl   (%edi)

# finally it call rb_gc_mark()

        call    rb_gc_mark

 ------------------------------------------------------------ 

 and you have the bug


 Now if you add `tmp' it will do exactly the same *except* at the end where
 it do


L166:
	subl	$12, %esp
	pushl	%ecx
.LCFI105:
	call	rb_gc_mark

 it call rb_gc_mark() with the right value




Guy Decoux

In This Thread