develooper Front page | perl.perl5.porters | Postings from August 2013

Re: When is PL_curcop NULL?

Thread Previous | Thread Next
From:
Nicholas Clark
Date:
August 8, 2013 09:30
Subject:
Re: When is PL_curcop NULL?
Message ID:
20130808093000.GL3729@plum.flirble.org
On Tue, Aug 06, 2013 at 01:11:56PM -0000, Father Chrysostomos wrote:
> Nicholas Clark wrote:
> > On Mon, Aug 05, 2013 at 09:07:53AM -0000, Father Chrysostomos wrote:
> > > Do we still need these [null] checks?
> > 
> > I think so, but I can't prove it. Moreover, I think that S_cop_free() should
> > have this:
> > 
> > +    if (PL_curcop == cop)
> > +       PL_curcop = NULL;
> >  }
> > 
> > 
> > because without that, we have an interpreter-global variable pointing to
> > freed memory. And that sort of dangling pointer has been the cause of
> > several different previous bugs.
> 
> I tried adding that block locally and *also* adding assert(PL_curcop)
> to newGP, and got no failures.  I think that both are a good idea.  We
> have many months before the next stable release and plenty of time to
> smoke out places where that assertion is wrong.  (And we will leave
> the null checks in newGP for now anyway, so non-debugging builds are
> not sabotaged.)

I even tried this, to make a flag that the tokenizer would check, so that it
would abort if it ever re-instated a freed COP to curcop, and all tests pass.
(Yes, I realise that this is attempting a read from freed memory, so it's not
perfect, and I didn't run it under ASAN, as the flat is too hot already,
without turning that machine on and giving it a serious workout)

diff --git a/op.c b/op.c
index d87396b..08c4908 100644
--- a/op.c
+++ b/op.c
@@ -217,6 +217,7 @@ Perl_Slab_Alloc(pTHX_ size_t sz)
            slot->opslot_next = slab2->opslab_first;    \
            slab2->opslab_first = slot;                 \
            o = &slot->opslot_op;                       \
+           o->op_freed = 0; \
            o->op_slabbed = 1
 
     /* The partially-filled slab is next in the chain. */
@@ -771,6 +772,7 @@ Perl_op_free(pTHX_ OP *o)
     }
 
     op_clear(o);
+    o->op_freed = 1;
     FreeOp(o);
 #ifdef DEBUG_LEAKING_SCALARS
     if (PL_op == o)
@@ -958,6 +960,9 @@ S_cop_free(pTHX_ COP* cop)
     if (! specialWARN(cop->cop_warnings))
        PerlMemShared_free(cop->cop_warnings);
     cophh_free(CopHINTHASH_get(cop));
+    if (PL_curcop == cop) {
+       PL_curcop = NULL;
+    }
 }
 
 STATIC void
diff --git a/op.h b/op.h
index dcfd5be..f85bca9 100644
--- a/op.h
+++ b/op.h
@@ -58,7 +58,8 @@ typedef PERL_BITFIELD16 Optype;
     PERL_BITFIELD16 op_savefree:1;     \
     PERL_BITFIELD16 op_static:1;       \
     PERL_BITFIELD16 op_folded:1;       \
-    PERL_BITFIELD16 op_spare:2;                \
+    PERL_BITFIELD16 op_freed:1;                \
+    PERL_BITFIELD16 op_spare:1;                \
     U8         op_flags;               \
     U8         op_private;
 #endif
diff --git a/toke.c b/toke.c
index 911fb94..c8f0d62 100644
--- a/toke.c
+++ b/toke.c
@@ -778,6 +778,7 @@ Perl_parser_free(pTHX_  const yy_parser *parser)
     PERL_ARGS_ASSERT_PARSER_FREE;
 
     PL_curcop = parser->saved_curcop;
+    assert(!PL_curcop->op_freed);
     SvREFCNT_dec(parser->linestr);
 
     if (PL_parser->lex_flags & LEX_DONT_CLOSE_RSFP)




Nicholas Clark

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About