diff options
author | Father Chrysostomos <sprout@cpan.org> | 2013-09-21 07:43:12 -0700 |
---|---|---|
committer | Father Chrysostomos <sprout@cpan.org> | 2013-09-21 07:44:06 -0700 |
commit | c947bc1dc2208798835a2ed509163cd71f20b218 (patch) | |
tree | 2ef445454c346ca20aa781fc139e896085187394 /gv.c | |
parent | 66ea08c616b11ff6bfed72f897895a6e21664769 (diff) | |
download | perl-c947bc1dc2208798835a2ed509163cd71f20b218.tar.gz |
Remove bad assertion in gv.c:newGP
See the thread starting at
<20130805090753.12203.qmail@lists-nntp.develooper.com>.
Under the assumption that PL_curcop could never be null in newGP (even
when set to null by S_cop_free in op.c), I added an assertion to
newGP, which still leaving the null checks in place. The idea was
that, if PL_curcop is ever null there, we want to know about it, since
it is probably a bug.
It turns out this code (reduced from DBIx::Class’s test suite), can
fail that assertion:
INIT {
bless {} and exit;
}
exit() calls leave_scope, which frees the INIT block. Since PL_curcop
(the statement inside INIT) would end up pointing to free memory, it
is set to null. When it exits, call_sv does FREETMPS:
case 2:
/* my_exit() was called */
SET_CURSTASH(PL_defstash);
FREETMPS;
JMPENV_POP;
my_exit_jump();
assert(0); /* NOTREACHED */
FREETMPS ends up freeing the object (bless {}), which results
in a DESTROY method lookup. For the sake of caching methods,
*main::DESTROY is autovivified. GV creation trips on the assertion in
newGP that makes sure PL_curcop is null.
So this proves that we really do need to check for a null
PL_curcop in newGP.
While we could avoid having DESTROY lookup vivify *main::DESTROY
(since the cache there would only be used for explicit ->DESTROY
calls, the usual DESTROY cache being stuffed into SvSTASH(stash)),
that would complicate things for no gain.
Diffstat (limited to 'gv.c')
-rw-r--r-- | gv.c | 7 |
1 files changed, 4 insertions, 3 deletions
@@ -176,9 +176,10 @@ Perl_newGP(pTHX_ GV *const gv) gp->gp_sv = newSV(0); #endif - /* PL_curcop should never be null here. */ - assert(PL_curcop); - /* But for non-debugging builds play it safe */ + /* PL_curcop may be null here. E.g., + INIT { bless {} and exit } + frees INIT before looking up DESTROY (and creating *DESTROY) + */ if (PL_curcop) { gp->gp_line = CopLINE(PL_curcop); /* 0 otherwise Newxz */ #ifdef USE_ITHREADS |