# New Ticket Created by Jerry Gay # Please include the string: [perl #43757] # in the subject line of all future correspondence about this issue. # <URL: http://rt.perl.org/rt3/Ticket/Display.html?id=43757 >
i made some small local mods while trying to debug a segfault during 'make test' for languages/perl6. the segfault occurs when running t/01-sanity/07-range.t. below is my patch. there's two changes in here, one for debugging, the other for better variable naming. since this patch causes a different segfault, i haven't separated the content of these two patches, as i'd like to nail this *new* segfault quickly so i can go back to *the other one*. --- Index: src/inter_call.c =================================================================== --- src/inter_call.c (revision 19728) +++ src/inter_call.c (working copy) @@ -23,6 +23,7 @@ #include <assert.h> #include "parrot/parrot.h" #include "parrot/oplib/ops.h" +#include "parrot/interpreter.h" #include "inter_call.str" /* HEADERIZER HFILE: include/parrot/inter_call.h */ @@ -325,27 +326,27 @@ static void -next_arg_sig(call_state_item *st /*NN*/) +next_arg_sig(call_state_item *sti /*NN*/) { - switch (st->mode & CALL_S_D_MASK) { + switch (sti->mode & CALL_S_D_MASK) { case CALL_STATE_OP: - st->sig = SIG_ITEM(st->u.op.signature, st->i); + sti->sig = SIG_ITEM(sti->u.op.signature, sti->i); break; case CALL_STATE_SIG: - switch (st->u.sig.sig[st->i]) { + switch (sti->u.sig.sig[sti->i]) { case 'I': - st->sig = PARROT_ARG_INTVAL; break; + sti->sig = PARROT_ARG_INTVAL; break; case 'N': - st->sig = PARROT_ARG_FLOATVAL; break; + sti->sig = PARROT_ARG_FLOATVAL; break; case 'S': - st->sig = PARROT_ARG_STRING; break; + sti->sig = PARROT_ARG_STRING; break; case 'O': case 'P': - st->sig = PARROT_ARG_PMC; break; + sti->sig = PARROT_ARG_PMC; break; case '@': - st->sig = PARROT_ARG_PMC | PARROT_ARG_SLURPY_ARRAY; break; + sti->sig = PARROT_ARG_PMC | PARROT_ARG_SLURPY_ARRAY; break; case 'F': - st->sig = PARROT_ARG_PMC | PARROT_ARG_FLATTEN; break; + sti->sig = PARROT_ARG_PMC | PARROT_ARG_FLATTEN; break; } break; } @@ -641,7 +642,8 @@ { PMC *key = UVal_pmc(st->val); - if (key && key->vtable->base_type == enum_class_Key) { +/* printf("PMC_IS_NULL(key) = %d\n", PMC_IS_NULL(key)); */ + if (!PMC_IS_NULL(key) && key->vtable && key->vtable->base_type == enum_clas s_Key) { for (; key; key=key_next(interp, key)) { /* register keys have to be cloned */ if (PObj_get_FLAGS(key) & KEY_register_FLAG) { --- as i mentioned, this causes another segfault--one when generating the tree grammar for compilers. c:\usr\local\parrot\trunk\compilers\past-pm>..\..\parrot ..\..\compilers\tge\tgc.pir --output =POST\Grammar_gen.pir POST\Grammar.tg here's the backtrace: --- libparrot.dll!Parrot_NameSpace_get_pointer_keyed(parrot_interp_t * interp=0x03ae2d80, PMC * pmc=0x03a17708, PMC * key=0x03c7b590) Line 342 + 0x6 bytes C libparrot.dll!fail_if_exist(parrot_interp_t * interp=0x03ae2d80, PMC * name=0x03c7b590) Line 258 + 0x1a bytes C libparrot.dll!Parrot_new_class(parrot_interp_t * interp=0x03ae2d80, PMC * _class=0x03ccced8, PMC * name=0x03c7b590) Line 582 + 0xd bytes C libparrot.dll!Parrot_ParrotClass_init_pmc(parrot_interp_t * interp=0x03ae2d80, PMC * pmc=0x03ccced8, PMC * name=0x03c7b590) Line 82 + 0x11 bytes C libparrot.dll!pmc_new_init(parrot_interp_t * interp=0x03ae2d80, long base_type=47, PMC * init=0x03c7b590) Line 318 + 0x1a bytes C > libparrot.dll!Parrot_newclass_p_pc(long * cur_opcode=0x039cf738, parrot_interp_t * interp=0x03ae2d80) Line 231 + 0x20 bytes C libparrot.dll!runops_slow_core(parrot_interp_t * interp=0x03ae2d80, long * pc=0x039cf738) Line 184 + 0x18 bytes C libparrot.dll!runops_int(parrot_interp_t * interp=0x03ae2d80, unsigned int offset=0) Line 787 + 0xb bytes C libparrot.dll!runops(parrot_interp_t * interp=0x03ae2d80, unsigned int offs=0) Line 95 + 0xd bytes C libparrot.dll!runops_args(parrot_interp_t * interp=0x03ae2d80, PMC * sub=0x03ccd1b8, PMC * obj=0x03a1be98, parrot_string_t * meth=0x00000000, const char * sig=0x102a06b8, char * ap=0x0017fb8c) Line 210 + 0xd bytes C libparrot.dll!Parrot_runops_fromc_args(parrot_interp_t * interp=0x03ae2d80, PMC * sub=0x03ccd1b8, const char * sig=0x102a06b8, ...) Line 287 + 0x1d bytes C libparrot.dll!run_sub(parrot_interp_t * interp=0x03ae2d80, PMC * sub_pmc=0x03ccd1b8) Line 375 + 0x12 bytes C libparrot.dll!do_1_sub_pragma(parrot_interp_t * interp=0x03ae2d80, PMC * sub_pmc=0x03ccd1b8, int action=2) Line 434 + 0xd bytes C libparrot.dll!do_sub_pragmas(parrot_interp_t * interp=0x03ae2d80, PackFile_ByteCode * self=0x039cf470, int action=2, PMC * eval_pmc=0x00000000) Line 566 + 0x11 bytes C libparrot.dll!PackFile_append_pbc(parrot_interp_t * interp=0x03ae2d80, const char * filename=0x03c1a720) Line 3250 + 0x17 bytes C libparrot.dll!Parrot_load_bytecode(parrot_interp_t * interp=0x03ae2d80, parrot_string_t * file_str=0x03bc0bb0) Line 3303 + 0xd bytes C libparrot.dll!Parrot_load_bytecode_sc(long * cur_opcode=0x03c04c88, parrot_interp_t * interp=0x03ae2d80) Line 149 + 0x1e bytes C libparrot.dll!runops_slow_core(parrot_interp_t * interp=0x03ae2d80, long * pc=0x03c04c88) Line 184 + 0x18 bytes C libparrot.dll!runops_int(parrot_interp_t * interp=0x03ae2d80, unsigned int offset=0) Line 787 + 0xb bytes C libparrot.dll!runops(parrot_interp_t * interp=0x03ae2d80, unsigned int offs=0) Line 95 + 0xd bytes C libparrot.dll!runops_args(parrot_interp_t * interp=0x03ae2d80, PMC * sub=0x03be3c20, PMC * obj=0x03a1be98, parrot_string_t * meth=0x00000000, const char * sig=0x102a06b8, char * ap=0x0017fd18) Line 210 + 0xd bytes C libparrot.dll!Parrot_runops_fromc_args(parrot_interp_t * interp=0x03ae2d80, PMC * sub=0x03be3c20, const char * sig=0x102a06b8, ...) Line 287 + 0x1d bytes C libparrot.dll!run_sub(parrot_interp_t * interp=0x03ae2d80, PMC * sub_pmc=0x03be3c20) Line 375 + 0x12 bytes C libparrot.dll!do_1_sub_pragma(parrot_interp_t * interp=0x03ae2d80, PMC * sub_pmc=0x03be3c20, int action=2) Line 434 + 0xd bytes C libparrot.dll!do_sub_pragmas(parrot_interp_t * interp=0x03ae2d80, PackFile_ByteCode * self=0x03c049f0, int action=2, PMC * eval_pmc=0x00000000) Line 566 + 0x11 bytes C libparrot.dll!PackFile_append_pbc(parrot_interp_t * interp=0x03ae2d80, const char * filename=0x03c19588) Line 3250 + 0x17 bytes C libparrot.dll!Parrot_load_bytecode(parrot_interp_t * interp=0x03ae2d80, parrot_string_t * file_str=0x03bc0e30) Line 3303 + 0xd bytes C libparrot.dll!Parrot_load_bytecode_sc(long * cur_opcode=0x03c19e4c, parrot_interp_t * interp=0x03ae2d80) Line 149 + 0x1e bytes C libparrot.dll!runops_slow_core(parrot_interp_t * interp=0x03ae2d80, long * pc=0x03c19e4c) Line 184 + 0x18 bytes C libparrot.dll!runops_int(parrot_interp_t * interp=0x03ae2d80, unsigned int offset=3) Line 787 + 0xb bytes C libparrot.dll!runops(parrot_interp_t * interp=0x03ae2d80, unsigned int offs=3) Line 95 + 0xd bytes C libparrot.dll!runops_args(parrot_interp_t * interp=0x03ae2d80, PMC * sub=0x03be3ea0, PMC * obj=0x03a1be98, parrot_string_t * meth=0x00000000, const char * sig=0x102a2d7c, char * ap=0x0017fea4) Line 210 + 0xd bytes C libparrot.dll!Parrot_runops_fromc_args(parrot_interp_t * interp=0x03ae2d80, PMC * sub=0x03be3ea0, const char * sig=0x102a2d7c, ...) Line 287 + 0x1d bytes C libparrot.dll!Parrot_runcode(parrot_interp_t * interp=0x03ae2d80, int argc=3, char * * argv=0x03ae2ce4) Line 783 + 0x16 bytes C libparrot.dll!imcc_run_pbc(parrot_interp_t * interp=0x03ae2d80, int obj_file=0, const char * output_file=0x00000000, int argc=3, char * * argv=0x03ae2ce4) Line 607 + 0x11 bytes C libparrot.dll!imcc_run(parrot_interp_t * interp=0x03ae2d80, const char * sourcefile=0x03ae2d19, int argc=3, char * * argv=0x03ae2ce4) Line 808 + 0x19 bytes C parrot.exe!main(int argc=3, char * * argv=0x03ae2ce4) Line 62 + 0x15 bytes C parrot.exe!__tmainCRTStartup() Line 586 + 0x17 bytes C kernel32.dll!772119f1() [Frames below may be incorrect and/or missing, no symbols loaded for kernel32.dll] ntdll.dll!77c1d109() --- the code bombs out at src/pmc/namespace.pmc:342 if (key->vtable->base_type == enum_class_String) { because 'key' is not a valid pmc, therefore ->vtable is not valid address. *boom* 'Parrot_NameSpace_get_pointer_keyed' has documentation that says: =item C<void* get_pointer_keyed(PMC *key)> Return the given namespace item or PMCNULL. If the named item is either a NameSpace or a var, the var is returned. TOTAL KLUDGE. ON THE CHOPPING BLOCK. =cut yuck. please, let's do something about that--and soon. but, the key passed into this function is invalid, so it's somewhere up the call chain. let's dig deeper.... tracing back through the call chain, i see this invalid pmc is passed through a number of calls, untouched. the pmc is created in Parrot_newclass_p_pc, which is the 'newclass' op in src/ops/object.ops. since the backtrace points directly to the .ops file, i can't see what's going on in the .c code without using an external editor. so i fire up 'gvim -t Parrot_newclass_p_pc' (andy++ for that time-saving hack) which brings me directly to the function (you have run 'make tags', haven't you?) here's what i find: opcode_t * Parrot_newclass_p_pc (opcode_t *cur_opcode, Interp *interp) { #line 231 "src\\ops\\object.ops" PREG(1) = pmc_new_init(interp, enum_class_ParrotClass, CONST(2)->u.key); return (opcode_t *)cur_opcode + 3; } unrolling several nested macros, PREG(1) converts to: (&(interp)->ctx)->bp_ps.regs_p[-1L-(cur_opcode[1])] looking inside, i can see this is a Null PMC. (&(interp)->ctx)->bp_ps.regs_p[-1L-(cur_opcode[1])]->vtable->isa_str->strstart 0x102a4c54 "Null" char * doing the same for CONST(2)->u.key: interp->ctx.state->constants[cur_opcode[2]] and again looking inside, i see this pmc constant is a Key for "TGE::Rule". interp->ctx.state->constants[cur_opcode[2]]->u.string->strstart 0x039eacac "TGE::Rule" char * now we're getting somewhere! using every parrot developer's favorite search tool, ack, i find all references to 'TGE::Rule' in the compilers directory: ack --all "TGE::Rule" compilers yields: Binary file compilers\tge\TGE\Grammar.pbc matches compilers\tge\TGE\Grammar.pir 31:of TGE::Rule objects, which are the semantics defined by the grammar. 56: rule = new 'TGE::Rule' Binary file compilers\tge\TGE\Rule.pbc matches compilers\tge\TGE\Rule.pir 5:TGE::Rule - a single rule in the attribute grammar 13:.namespace [ "TGE::Rule" ] 20: newclass base, "TGE::Rule" HEY! lookie there, compilers/tge/TGE/Rule.pir contains 'newclass base, "TGE::Rule"'. that's exactly what i'm looking for. now i know where this invalid pmc comes from. but *why* is it invalid? AARGH! okay, this is the part where i recompile parrot after adding some debugging code, and the segfault *moves*. ain't that grand? it hasn't moved far, though. it still occurs during the same command-line command. but, now it's in the 'subclass' op (which is earlier than before.) luckily, using the structures i added to my watch list (and adding one more) tell me it's running something like: $P0 = subclass 'PGE::Grammar', 'TGE::Parser' that happens to be line 5 of compilers/tge/TGE/Parser.pir (generated by pgc.pir from Parser.pg in that same directory.) here's the source for the subclass op: opcode_t * Parrot_subclass_p_pc_pc (opcode_t *cur_opcode, Interp *interp) { #line 341 "src\\ops\\object.ops" PMC *_class = Parrot_class_lookup_p(interp, CONST(2)->u.key); opcode_t *next = cur_opcode + 4; if (PMC_IS_NULL(_class)) { STRING *name = readable_name(interp, CONST(2)->u.key); real_exception(interp, next, NO_CLASS, "Class '%Ss' doesn't exist", name); } PREG(1) = VTABLE_subclass(interp, _class, CONST(3)->u.key); return (opcode_t *)next; } hey, look at that! here's what my debugger shows for the structure known above as CONST(2)->u.key (which is equivalent to $2 in the .ops file before ops2c.pl gets it's hands on it): - interp->ctx.state->constants[cur_opcode[2]]->u.key 0x03b7a1e0 {obj={...} vtable=0x0000000c real_self=0x038ab1c4 ...} PMC * + obj {u={...} flags=397568 } pobj_t + vtable 0x0000000c {_namespace=??? base_type=??? whoami=??? ...} _vtable * + real_self 0x038ab1c4 {obj={...} vtable=0x3a454754 real_self=0x7261503a ...} PMC * + pmc_ext 0x0000000c {data=??? _metadata=??? _synchronize=??? ...} PMC_EXT * that's an *totally* uninitialized key. here's what i don't get: why is it expecting a key, anyway? i mean, the op is getting two pir strings. $P0 = subclass 'PGE::Grammar', 'TGE::Parser' why isn't that calling subclass_p_sc_sc? if it were: $P0 = subclass ['PGE::Grammar'], ['TGE::Parser'] then i'd expect it to call subclass_p_pc_pc (or perhaps subclass_p_kc_kc.) well, at this point, i can't recreate the segfault, but i still have questions about why that particular op is being called. please, can someone enlighten me? it's knowledge that will definitely come in handy when debugging in the future. ~jerry