When I run the t/01-sanity/06-use.t test in languages/perl6, I get an 
assertion failure:

        parrot: src/string.c:2028: string_hash: Assertion `s->encoding && 
s->charset 
&& !(((s)->obj.flags) & b_PObj_on_free_list_FLAG)' failed.

This happens when trying to hash a string (specifically the 
string 'Perl6::Grammar::quote_term').  I dug into this a little bit.  It's 
the last test that fails; the string IS on the free list.  Something isn't 
marking it as live appropriately.

Here's the backtrace:

Program received signal SIGABRT, Aborted.
[Switching to Thread -1212417840 (LWP 15328)]
0xffffe410 in __kernel_vsyscall ()
(gdb) bt
#0  0xffffe410 in __kernel_vsyscall ()
#1  0x4d068df0 in raise () from /lib/tls/i686/cmov/libc.so.6
#2  0x4d06a641 in abort () from /lib/tls/i686/cmov/libc.so.6
#3  0x4d06243b in __assert_fail () from /lib/tls/i686/cmov/libc.so.6
#4  0xb7dbbc0d in string_hash (interp=0x804e008, s=0x81e1600, seed=3793)
    at src/string.c:2028
#5  0xb7dc30be in key_hash_STRING (interp=0x804e008, value=0x81e1600, 
    seed=3793) at src/hash.c:57
#6  0xb7dc3dee in parrot_hash_get_bucket (interp=0x804e008, hash=0x805d138, 
    key=0x81e1600) at src/hash.c:726
#7  0xb7ea2663 in Parrot_Hash_exists_keyed (interp=0x804e008, pmc=0x82ab8b0, 
    key=0x0) at ./src/pmc/hash.pmc:900
#8  0xb7cd1f1b in Parrot_exists_i_p_kc (cur_opcode=0xb6af4230, 
    interp=0x804e008) at src/ops/pmc.ops:327
#9  0xb7dbe35b in runops_slow_core (interp=0x804e008, pc=0xb6af4230)
    at src/runops_cores.c:184
#10 0xb7da8d5e in runops_int (interp=0x804e008, offset=58)
    at src/interpreter.c:779

I poked around some more and found out that the string is in a Key PMC (okay, 
that's obvious from the backtrace).  I can't see that the Key itself is 
getting marked as live, which is a problem.

The problem is that the actual string is in a register, in 
TGE::Tree::_scan_node(), lines 66 - 75:

    # Iterate over the elements of the visit hash for the given type
    .local pmc actions
    .local int index
    .local pmc currule
    $P2 = getattribute self, 'visit'
    $I2 = exists $P2[type]
    unless $I2 goto end_loop
    actions = $P2[type]
    index = actions

That exists call is frame #8 in the backtrace.

It makes *some* sense that the Key PMC created for that call doesn't mark the 
String explicitly.  It's sort of a temporary thing (and the String has a flag 
set marking that it's in a register).

I wondered if register values weren't getting marked as live appropriately.  I 
dug into mark_context() in src/sub.c and annotated that, to see if the string 
does get marked.  (String registers do get marked as live.)

Then I had an insight.  There's no guarantee that a GC run will occur unless 
you force it, so I forced it in TGE::Tree just before the exists call:

    .local pmc interp
    interp = getinterp
    interp.'run_gc'()
    $P2 = getattribute self, 'visit'
    $I2 = exists $P2[type]

The test then passed.  The assertion was okay.  The String is obviously live, 
after it gets marked as live.  I then wondered if strings get marked as live 
when they're created.  The answer was in new_string_header() in 
src/headers.c:

        PObj_get_FLAGS(string) |= flags 
|PObj_is_string_FLAG|PObj_is_COWable_FLAG;

I changed it:

        PObj_get_FLAGS(string) |= flags |
                PObj_is_string_FLAG | PObj_is_COWable_FLAG | PObj_live_FLAG;

Adding the live flag fixed the problem (r18855).

Alternately, deleting that part of the assertion wouldn't entirely suck 
either.  I'm not sure that anyone has dug into the encoding problem though, 
so it ought to stay until we're sure that things work.

-- c

Reply via email to