rb_gc() and scan stack

  • Thread starter Simon Strandgaard
  • Start date
S

Simon Strandgaard

I were experimenting with Init_stack, when I discovered a flaw in my mind.

I thought that: local variables on stack would be marked in the
mark-phase and therefore survive the sweep-phase.

But my instance is being destroyed.. why ?

Can someone enligthen me ?

expand -t4 rb_gc1.c
#include <ruby.h>

void Dummy_Free(void *p) {
printf("free\n");
delete [] ((int*)p);
}

VALUE Dummy_Alloc(VALUE self) {
printf("alloc\n");
int *p = new int[1];
return Data_Wrap_Struct(self, 0, Dummy_Free, p);
}

VALUE Dummy_Initialize(VALUE self) {
int *p;
printf("initialize\n");
Data_Get_Struct(self, int, p);
return self;
}

void Init_dummy() {
VALUE h = rb_define_class("Dummy", rb_cObject);
rb_define_alloc_func(h, Dummy_Alloc);
typedef VALUE (*HOOK)(...);
rb_define_method(h, "initialize", (HOOK)(&Dummy_Initialize), 0);
}

VALUE tst_new_dummy() {
return rb_class_new_instance(0, 0, rb_path2class("Dummy"));
}

void test() {
VALUE instance = tst_new_dummy();
printf("1\n");
rb_p(instance);
// the instance SHOULD survive this step (1_2)
rb_gc();
printf("2\n");
rb_p(instance);
// the instance should NOT survive this step (2_3)
instance = Qnil;
rb_gc();
printf("3\n");
rb_p(instance);
}

int main(int argc, char **argv) {
ruby_init();
Init_dummy();
test();
return 0;
}
alloc
initialize
1
#<Dummy:0x8103b38>
free
2
ruby: [BUG] Segmentation fault
ruby 1.8.0 (2003-06-23) [i386-freebsd5.0]

Abort (core dumped)

As you can see the 'free' is occuring between '1' and '2'.

I thought 'free' was suppose to happen between '2' and '3' ?
Expecting output should look like this:

alloc
initialize
1
#<Dummy:0x8103b38>
2
#<Dummy:0x8103b38>
free
3
ruby: [BUG] Segmentation fault
ruby 1.8.0 (2003-06-23) [i386-freebsd5.0]

Abort (core dumped)
 
Y

Yukihiro Matsumoto

Hi,

In message "Re: rb_gc() and scan stack"

|> Im *still* confused about the rb_gc_stack_start value in my first posting.
|> Why does it fail in step (1_2), Can someone enligthen me ???
|
|Guy Decoux + others.. I know you are reading this.. please help :)

We can't say much. As far as I guess stack, position was higher than
the position where Init_stack() was called from ruby_init().

matz.
 
S

Simon Strandgaard

I were experimenting with Init_stack, when I discovered a flaw in my mind.

I thought that: local variables on stack would be marked in the
mark-phase and therefore survive the sweep-phase.

But my instance is being destroyed.. why ?

Can someone enligthen me ? [...]
int main(int argc, char **argv) {
ruby_init();
Init_dummy();
test();
return 0;
}

Could you please check if adding one stack frame in between works?
If it does, it'd mean it's exactly the same issue described in the links
I provided some time ago, that is, that ruby_init is capturing the
current SP to record the beginning of the stack, but you're storing
VALUEs in a stack frame above.

Please test adding the following to your code: [snip]

Cannot check now as my primary machine has no connection and the one
I'm writing from has no ruby...


It doesn't help.. my main now looks like this:
expand -t4 main.c | tail -n12
void foo() {
int a, b, c, d, e, f; /* just to take place in the stack */
a = b = c = d = e = f = 1; /* don't get warnings when -Wall */
test();
}

int main(int argc, char **argv) {
ruby_init();
Init_dummy();
foo();
return 0;
}
Output is the same:
alloc
initialize
1
#<Dummy:0x8103b38>
free
2
ruby: [BUG] Segmentation fault
ruby 1.8.0 (2003-06-23) [i386-freebsd5.0]

Abort (core dumped)
I tried drawing on some paper, what is happening..
My initial drawing were wrong.. Now I understand.
No problemo:

The stack grows againts right.

'.' = empty stack range (unkown to GC).
'R' = stack range scanned by GC.
left-most-R == rb_gc_stack_end.
right-most-R == rb_gc_stack_begin (set by Init_stack).
'|' = current stack pointer.
'i' = where the instance is on the stack.


--[ 0 ]-----------------
top/hi [.....................] bottom/lo
|

--[ 1 ]-----------------
entering ruby_init()
top/hi [.....................] bottom/lo
|

--[ 2 ]-----------------
leaving ruby_init()
top/hi [RRRRR................] bottom/lo
|

--[ 3 ]-----------------
entering Init_dummy()
top/hi [RRRRR................] bottom/lo
|

--[ 4 ]-----------------
leaving Init_dummy()
top/hi [RRRRR................] bottom/lo
|

--[ 5 ]-----------------
entering test()
top/hi [RRRRR................] bottom/lo
|

--[ 6 ]-----------------
instance = Dummy.new
The instance is not within the mark-area, therefore it dies!
top/hi [RRRRR..i.............] bottom/lo
|

--[ 7 ]-----------------
rb_gc(); /* first time */

The instance is not within the RRRRR range... and
Ruby is therefore unable to mark the instance.
Thus it dies!

top/hi [RRRRR................] bottom/lo
|


If we redo from step6 with Init_stack(begin).. with a
lower begin address, then things will work.

--[ 6a ]-----------------
Init_stack(current_stack_ptr)
top/hi [RRRRRRRR.............] bottom/lo
|

--[ 7a ]-----------------
instance = Dummy.new
This time the instance is within the area, and will thus survive
top/hi [RRRRRRRR.............] bottom/lo
|

--[ 8a ]-----------------
rb_gc(); /* first time: this time we survie */
top/hi [RRRRRRRR.............] bottom/lo
|

--[ 9a ]-----------------
i = nil
top/hi [RRRRRRRR.............] bottom/lo
|

--[ 10a ]-----------------
rb_gc(); /* second time: this time we die */
top/hi [RRRRRRRR.............] bottom/lo
|

--[ 11a ]-----------------
leaving test();
top/hi [RRRRRRRR.............] bottom/lo
|
 
N

nobu.nokada

Hi,

At Wed, 2 Jul 2003 22:18:15 +0900,
Simon said:
I tried drawing on some paper, what is happening..
My initial drawing were wrong.. Now I understand.
No problemo:

Incorrect.

G == rb_gc_stack_start (set by Init_stack).

--[ 0 ]-----------------
bottom [.....................] top
|

--[ 1 ]-----------------
entering ruby_init()
bottom [.......G.............] top
|

--[ 2 ]-----------------
leaving ruby_init()
bottom [.RRRRRRG.............] top
|

--[ 3 ]-----------------
entering Init_dummy()
bottom [..RRRRRG.............] top
|

--[ 4 ]-----------------
leaving Init_dummy()
bottom [.RRRRRRG.............] top
|

--[ 5 ]-----------------
entering test()
bottom [......RG.............] top
|

--[ 6 ]-----------------
instance = Dummy.new
The instance is not within the mark-area, therefore it dies!
bottom [....i.RG.............] top
|
If we redo from step6 with Init_stack(begin).. with a
lower begin address, then things will work.

--[ 6a ]-----------------
Init_stack(current_stack_ptr)
bottom [...G.................] top
|

--[ 7a ]-----------------
instance = Dummy.new
This time the instance is within the area, and will thus survive
bottom [...GRiR..............] top
|
 
S

Simon Strandgaard

At Wed, 2 Jul 2003 22:18:15 +0900,


Incorrect.

I have some major/minor problems understanding your diagram.

What confuses me is that 'G' is right-most in step 1-6.
And that 'G' is left-most in step 7a.
This seems odd to me, Is this really correct behavier ?

I should have mentionen that I am talking about a x86 stack
which grows downward. In my posting the stack therefore had
its high-addeses to the left.. and the lower addesses at right.
I see you have swapped 'bottom' with 'top'.. this confuses me.
Are you refering to a x86 stack or a motorola stack ?


Thanks Nobu for the otherwise nice diagram :)
 
N

nobu.nokada

Hi,

At Thu, 3 Jul 2003 01:00:35 +0900,
Simon said:
What confuses me is that 'G' is right-most in step 1-6.
And that 'G' is left-most in step 7a.
This seems odd to me, Is this really correct behavier ?

It *was* correct. To be accurate, nothing shouldn't be marked
in step 2 through 6. But rb_gc_mark_locations(), which marks
stack, swaps its arguments when they are out of order. So
garbages would possibly be marked.

# I forgot to remove this now useless code.
I should have mentionen that I am talking about a x86 stack
which grows downward. In my posting the stack therefore had
its high-addeses to the left.. and the lower addesses at right.
I see you have swapped 'bottom' with 'top'.. this confuses me.
Are you refering to a x86 stack or a motorola stack ?

Both x86 and mc68000 stacks grow downward. IIRC, beginning of
stack is called "bottom", and the edge where an element is
pushed into and popped from is called "top".
 
S

Simon Strandgaard

It *was* correct. To be accurate, nothing shouldn't be marked
in step 2 through 6. But rb_gc_mark_locations(), which marks
stack, swaps its arguments when they are out of order. So
garbages would possibly be marked.

"swaps its arguments"... I oversaw this.
About 5 minuts I just realized this, browsing 'gc.c' :)


Thanks Nobu.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

Function is not worked in C 2
Fibonacci 0
[setjmp/longjmp] stack limitation 17
Array implementation of Stack 80
Stack 9
Stack using doubly linked list 1
stack & passing variables 8
stack smashing 63

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,051
Latest member
CarleyMcCr

Latest Threads

Top