Oh, yay. Orange tinderboxen rule, only because I haven't seen that much orange in quite awhile. :)
Anyways, I looked into the bug. There's actually a few problems...First, is that perlstrings use the structval to store the buffer, and so it gets missed by the GC. The patch below fixes perlstring to use the data pointer like the GC wants. (And the other perl* classes, to use perlstring's data pointer. What happened to the encapsulation in calling set_number, etc?) Then I found a small GC bug where it was trying to buffer_lives on a null pointer. Below patch fixes this as well. Then there was *still* corruption. I thought this is the 'GC before I've done anything with it' problem. When I create a new pmc, it calls init() before the pmc gets put into the reg table. If the vtable init() creates a new string (PerlString does this), then it's possible a dod run will occur, and cause the as-yet-unassigned PMC to be incorrectly freed. Below patch marks it as immortal for the duration of the init() call. This finally fixed the problem. :) While I was at it, I also made string_copy set the 'live' flag on the newly-created string, such that when it calls Parrot_allocate for the string's contents, a call to Parrot_go_collect will not forget to copy our new string. Note, there is one 'big' problem with this patch. It makes it impossible to make constant pmc's using the init() vtable method, since it unsets the flag after calling the function. Perhaps we should make a private GC flag, PMC_private_constant_FLAG, or something, which the PMCs should *never* use, and is reserved for the GC, in cases like these. Regardless, this patch does make 'make test' happy again, and should be safe to apply apply, as long as we don't forget about the afore-mentioned caveat, which will probably come back to bite us in the future if we don't take care of it. I wonder how many more GC bugs are lurking, waiting for good tests cases like these.. Mike Lambert Josh Wilmes wrote: > Date: Thu, 28 Mar 2002 02:52:15 -0500 > From: Josh Wilmes <[EMAIL PROTECTED]> > To: [EMAIL PROTECTED] > Subject: Re: "deep" tests for stacks.t > > > Mike pointed out that I was missing "end" opcodes in there, so I added > them and went ahead and committed this code to CVS. Currently test #7 is > failing, but I think it's a legitimate bug- if not, I apologize for > breaking the tinderbox ;) > > --Josh > > At 1:15 on 03/28/2002 EST, Josh Wilmes <[EMAIL PROTECTED]> wrote: > > > > > I added some tests which push larger numbers of stack frames- this > > improves our coverage in register.c. However, one of the tests is failing > > for me. Is this something I did wrong, or did I find a bug? > > > > I'm getting weird output for the pushp and popp (deep) test. > > > > --Josh > > > > Here's the patch: > > > > Index: t/op/stacks.t > > =================================================================== > > RCS file: /cvs/public/parrot/t/op/stacks.t,v > > retrieving revision 1.12 > > diff -u -r1.12 stacks.t > > --- t/op/stacks.t 29 Jan 2002 02:32:17 -0000 1.12 > > +++ t/op/stacks.t 28 Mar 2002 06:12:31 -0000 > > @@ -1,6 +1,6 @@ > > #! perl -w > > > > -use Parrot::Test tests => 15; > > +use Parrot::Test tests => 18; > > use Test::More; > > > > # Tests for stack operations, currently push*, push_*_c and pop* > > @@ -87,6 +87,23 @@ > > 3031 > > OUTPUT > > > > + > > +my ($code, $output); > > +for (0..1024) { > > + $code .= " set I0, $_\n"; > > + $code .= " set I31, " . (1024-$_) . "\n"; > > + $code .= " pushi\n"; > > +} > > +for (0..1024) { > > + $code .= " popi\n"; > > + $code .= " print I0\n"; > > + $code .= " print I31\n"; > > + $code .= " print \"\\n\"\n"; > > + $output .= (1024-$_) . "$_\n"; > > +} > > +output_is($code, $output, "pushi & popi (deep)" ); > > + > > + > > output_is(<<"CODE", <<'OUTPUT', 'pushs & pops'); > > @{[ set_str_regs( sub {$_[0]%2} ) ]} > > pushs > > @@ -102,6 +119,23 @@ > > 01010101010101010101010101010101 > > OUTPUT > > > > + > > +($code, $output) = (); > > +for (0..1024) { > > + $code .= " set S0, \"$_\"\n"; > > + $code .= " set S31, \"" . (1024-$_) . "\"\n"; > > + $code .= " pushs\n"; > > +} > > +for (0..1024) { > > + $code .= " pops\n"; > > + $code .= " print S0\n"; > > + $code .= " print S31\n"; > > + $code .= " print \"\\n\"\n"; > > + $output .= (1024-$_) . "$_\n"; > > +} > > +output_is($code, $output, "pushs & pops (deep)" ); > > + > > + > > output_is(<<"CODE", <<'OUTPUT', 'pushn & popn'); > > @{[ set_num_regs( sub { "1.0".$_ } ) ]} > > pushn > > @@ -119,6 +153,7 @@ > > Seem to have positive Nx after pop > > OUTPUT > > > > + > > output_is(<<"CODE", <<'OUTPUT', 'pushp & popp'); > > new P0, PerlString > > set P0, "BUTTER IN HELL!\\n" > > @@ -132,6 +167,25 @@ > > CODE > > THERE'LL BE NO BUTTER IN HELL! > > OUTPUT > > + > > + > > +($code, $output) = (); > > +for (0..1024) { > > + $code .= " new P0, PerlString\n"; > > + $code .= " new P31, PerlString\n"; > > + $code .= " set P0, \"$_\"\n"; > > + $code .= " set P31, \"" . (1024-$_) . "\"\n"; > > + $code .= " pushp\n"; > > +} > > +for (0..1024) { > > + $code .= " popp\n"; > > + $code .= " print P0\n"; > > + $code .= " print P31\n"; > > + $code .= " print \"\\n\"\n"; > > + $output .= (1024-$_) . "$_\n"; > > +} > > +output_is($code, $output, "pushp & popp (deep)" ); > > + > > > > # Test proper stack chunk handling > > output_is(<<CODE, <<'OUTPUT', 'save_i & restore_i'); > > > > > > >
Index: parrot/pmc.c =================================================================== RCS file: /cvs/public/parrot/pmc.c,v retrieving revision 1.11 diff -u -r1.11 pmc.c --- parrot/pmc.c 10 Mar 2002 21:19:46 -0000 1.11 +++ parrot/pmc.c 28 Mar 2002 10:18:33 -0000 @@ -52,7 +52,11 @@ return NULL; } + /* This flag gets turned off in a second anyway. + This ensures the string survives Parrot_do_dod_run */ + pmc->flags |= PMC_constant_FLAG | PMC_live_FLAG; pmc->vtable->init(interpreter, pmc, 0); + pmc->flags &= ~PMC_constant_FLAG; return pmc; } @@ -80,7 +84,11 @@ return NULL; } + /* This flag gets turned off in a second anyway. + This ensures the string survives Parrot_do_dod_run */ + pmc->flags |= PMC_constant_FLAG | PMC_live_FLAG; pmc->vtable->init(interpreter, pmc, size); + pmc->flags &= ~PMC_constant_FLAG; return pmc; } Index: parrot/resources.c =================================================================== RCS file: /cvs/public/parrot/resources.c,v retrieving revision 1.35 diff -u -r1.35 resources.c --- parrot/resources.c 26 Mar 2002 16:33:01 -0000 1.35 +++ parrot/resources.c 28 Mar 2002 10:18:34 -0000 @@ -420,7 +420,9 @@ } else { if (bits == PMC_is_buffer_ptr_FLAG) { - buffer_lives(current->data); + if (current->data) { + buffer_lives(current->data); + } } else { /* The only thing left is "buffer of PMCs" */ Index: parrot/string.c =================================================================== RCS file: /cvs/public/parrot/string.c,v retrieving revision 1.64 diff -u -r1.64 string.c --- parrot/string.c 24 Mar 2002 06:57:28 -0000 1.64 +++ parrot/string.c 28 Mar 2002 10:18:34 -0000 @@ -166,6 +166,9 @@ { STRING *d; d = new_string_header(interpreter); + /* This flag gets reset in a bit anyway. + This ensures the string survives Parrot_go_collect */ + d->flags = BUFFER_live_FLAG; d->bufstart = Parrot_allocate(interpreter, s->buflen); d->buflen = s->buflen; d->flags = s->flags & (~(unsigned int)BUFFER_constant_FLAG); Index: parrot/classes/perlint.pmc =================================================================== RCS file: /cvs/public/parrot/classes/perlint.pmc,v retrieving revision 1.17 diff -u -r1.17 perlint.pmc --- parrot/classes/perlint.pmc 10 Mar 2002 21:18:13 -0000 1.17 +++ parrot/classes/perlint.pmc 28 Mar 2002 10:18:36 -0000 @@ -119,27 +119,27 @@ void set_string (PMC * value) { SELF->vtable = &(Parrot_base_vtables[enum_class_PerlString]); - SELF->cache.struct_val = value->cache.struct_val; + SELF->data = value->cache.struct_val; } void set_string_native (STRING * value) { SELF->vtable = &(Parrot_base_vtables[enum_class_PerlString]); - SELF->cache.struct_val = value; + SELF->data = value; } void set_string_unicode (STRING * value) { SELF->vtable = &(Parrot_base_vtables[enum_class_PerlString]); - SELF->cache.struct_val = value; + SELF->data = value; } void set_string_other (STRING * value) { SELF->vtable = &(Parrot_base_vtables[enum_class_PerlString]); - SELF->cache.struct_val = value; + SELF->data = value; } void set_string_same (PMC * value) { SELF->vtable = &(Parrot_base_vtables[enum_class_PerlString]); - SELF->cache.struct_val = value->cache.struct_val; + SELF->data = value->cache.struct_val; } void set_value (void* value) { Index: parrot/classes/perlnum.pmc =================================================================== RCS file: /cvs/public/parrot/classes/perlnum.pmc,v retrieving revision 1.19 diff -u -r1.19 perlnum.pmc --- parrot/classes/perlnum.pmc 10 Mar 2002 21:18:13 -0000 1.19 +++ parrot/classes/perlnum.pmc 28 Mar 2002 10:18:36 -0000 @@ -117,27 +117,27 @@ void set_string (PMC * value) { SELF->vtable = &(Parrot_base_vtables[enum_class_PerlString]); - SELF->cache.struct_val = value->cache.struct_val; + SELF->data = value->cache.struct_val; } void set_string_native (STRING * value) { SELF->vtable = &(Parrot_base_vtables[enum_class_PerlString]); - SELF->cache.struct_val = value; + SELF->data = value; } void set_string_unicode (STRING * value) { SELF->vtable = &(Parrot_base_vtables[enum_class_PerlString]); - SELF->cache.struct_val = value; + SELF->data = value; } void set_string_other (STRING * value) { SELF->vtable = &(Parrot_base_vtables[enum_class_PerlString]); - SELF->cache.struct_val = value; + SELF->data = value; } void set_string_same (PMC * value) { SELF->vtable = &(Parrot_base_vtables[enum_class_PerlString]); - SELF->cache.struct_val = value->cache.struct_val; + SELF->data = value->cache.struct_val; } void set_value (void* value) { Index: parrot/classes/perlstring.pmc =================================================================== RCS file: /cvs/public/parrot/classes/perlstring.pmc,v retrieving revision 1.18 diff -u -r1.18 perlstring.pmc --- parrot/classes/perlstring.pmc 10 Mar 2002 21:18:13 -0000 1.18 +++ parrot/classes/perlstring.pmc 28 Mar 2002 10:18:36 -0000 @@ -23,12 +23,13 @@ } void init (INTVAL size) { - SELF->cache.struct_val = string_make(INTERP,NULL,0,NULL,0,NULL); + SELF->data = string_make(INTERP,NULL,0,NULL,0,NULL); + SELF->flags = PMC_is_buffer_ptr_FLAG; } void clone (PMC* dest) { dest->vtable = SELF->vtable; - dest->cache.struct_val = string_copy(INTERP,SELF->cache.struct_val); + dest->data = string_copy(INTERP,SELF->data); } void morph (INTVAL type) { @@ -43,25 +44,25 @@ } void destroy () { - string_destroy(SELF->cache.struct_val); + string_destroy(SELF->data); } INTVAL get_integer () { - STRING* s = (STRING*) SELF->cache.struct_val; + STRING* s = (STRING*) SELF->data; return string_to_int(s); } FLOATVAL get_number () { - STRING* s = (STRING*) SELF->cache.struct_val; + STRING* s = (STRING*) SELF->data; return string_to_num(s); } STRING* get_string () { - return (STRING*)SELF->cache.struct_val; + return (STRING*)SELF->data; } BOOLVAL get_bool () { - return string_bool(SELF->cache.struct_val); + return string_bool(SELF->data); } void* get_value () { @@ -69,8 +70,8 @@ } BOOLVAL is_same (PMC* other) { - STRING* s1 = (STRING*)SELF->cache.struct_val; - STRING* s2 = (STRING*)other->cache.struct_val; + STRING* s1 = (STRING*)SELF->data; + STRING* s2 = (STRING*)other->data; return (BOOLVAL)( other->vtable == SELF->vtable && s1->bufused == s2->bufused && (memcmp(s1->bufstart,s2->bufstart,(size_t)s1->bufused)==0)); @@ -113,29 +114,29 @@ } void set_string (PMC * value) { - SELF->cache.struct_val = - string_copy(INTERP, (STRING*)value->cache.struct_val); + SELF->data = + string_copy(INTERP, (STRING*)value->data); } void set_string_native (STRING * value) { - SELF->cache.struct_val = string_copy(INTERP, value); + SELF->data = string_copy(INTERP, value); } void set_string_unicode (STRING * value) { - SELF->cache.struct_val = string_copy(INTERP, value); + SELF->data = string_copy(INTERP, value); } void set_string_other (STRING * value) { - SELF->cache.struct_val = string_copy(INTERP, value); + SELF->data = string_copy(INTERP, value); } void set_string_same (PMC * value) { - SELF->cache.struct_val = - string_copy(INTERP, (STRING*)value->cache.struct_val); + SELF->data = + string_copy(INTERP, (STRING*)value->data); } void set_value (void* value) { - SELF->cache.struct_val = value; + SELF->data = value; } void add (PMC * value, PMC* dest) { @@ -347,54 +348,54 @@ } void concatenate (PMC * value, PMC* dest) { - STRING* s = string_copy(INTERP, (STRING*)SELF->cache.struct_val); - dest->cache.struct_val = + STRING* s = string_copy(INTERP, (STRING*)SELF->data); + dest->data = string_concat(INTERP, s, value->vtable->get_string(INTERP, value), 0 ); - /* don't destroy s, as it is dest->cache.struct_val */ + /* don't destroy s, as it is dest->data */ } void concatenate_native (STRING * value, PMC* dest) { - STRING* s = string_copy(INTERP, (STRING*)SELF->cache.struct_val); - dest->cache.struct_val = + STRING* s = string_copy(INTERP, (STRING*)SELF->data); + dest->data = string_concat(INTERP, s, value, 0 ); - /* don't destroy s, as it is dest->cache.struct_val */ + /* don't destroy s, as it is dest->data */ } void concatenate_unicode (STRING * value, PMC* dest) { - STRING* s = string_copy(INTERP, (STRING*)SELF->cache.struct_val); - dest->cache.struct_val = + STRING* s = string_copy(INTERP, (STRING*)SELF->data); + dest->data = string_concat(INTERP, s, value, 0 ); - /* don't destroy s, as it is dest->cache.struct_val */ + /* don't destroy s, as it is dest->data */ } void concatenate_other (STRING * value, PMC* dest) { - STRING* s = string_copy(INTERP, (STRING*)SELF->cache.struct_val); - dest->cache.struct_val = + STRING* s = string_copy(INTERP, (STRING*)SELF->data); + dest->data = string_concat(INTERP, s, value, 0 ); - /* don't destroy s, as it is dest->cache.struct_val */ + /* don't destroy s, as it is dest->data */ } void concatenate_same (PMC * value, PMC* dest) { - dest->cache.struct_val = + dest->data = string_concat(INTERP, - SELF->cache.struct_val, - value->cache.struct_val, + SELF->data, + value->data, 0 ); } @@ -402,7 +403,7 @@ /* == operation */ BOOLVAL is_equal (PMC* value) { return (BOOLVAL)( 0 == string_compare(INTERP, - SELF->cache.struct_val, + SELF->data, value->vtable->get_string(INTERP, value) )); } @@ -430,40 +431,40 @@ void repeat (PMC * value, PMC* dest) { dest->vtable = &Parrot_base_vtables[enum_class_PerlString]; - dest->cache.struct_val = - string_repeat(INTERP, SELF->cache.struct_val, + dest->data = + string_repeat(INTERP, SELF->data, (UINTVAL)value->vtable->get_integer(INTERP, value), NULL ); } void repeat_native (STRING * value, PMC* dest) { dest->vtable = &Parrot_base_vtables[enum_class_PerlString]; - dest->cache.struct_val = - string_repeat(INTERP, SELF->cache.struct_val, + dest->data = + string_repeat(INTERP, SELF->data, (UINTVAL)string_to_int(value), NULL ); } void repeat_unicode (STRING * value, PMC* dest) { dest->vtable = &Parrot_base_vtables[enum_class_PerlString]; - dest->cache.struct_val = - string_repeat(INTERP, SELF->cache.struct_val, + dest->data = + string_repeat(INTERP, SELF->data, (UINTVAL)string_to_int(value), NULL ); } void repeat_other (STRING * value, PMC* dest) { dest->vtable = &Parrot_base_vtables[enum_class_PerlString]; - dest->cache.struct_val = - string_repeat(INTERP, SELF->cache.struct_val, + dest->data = + string_repeat(INTERP, SELF->data, (UINTVAL)string_to_int(value), NULL ); } void repeat_same (PMC * value, PMC* dest) { dest->vtable = &Parrot_base_vtables[enum_class_PerlString]; - dest->cache.struct_val = - string_repeat(INTERP, SELF->cache.struct_val, + dest->data = + string_repeat(INTERP, SELF->data, (UINTVAL)value->vtable->get_integer(INTERP, value), NULL ); }