# 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

Reply via email to