Stop eval "BEGIN{die}" from leaking
This fixes the rest of [perl #78438].
eval "BEGIN{die}" creates a *{"_<(eval 1)"} glob regardless of $^P’s
setting in non-threaded builds as of change f9bddea (5.12.0).
Here are the results with various configurations:
version threaded eval text $^P Is *{"_<(eval 1)"} set?
------- -------- --------- --- -----------------------
5.10.1 yes BEGIN{} 0 no
5.10.1 yes BEGIN{die} 0 no
5.10.1 yes BEGIN{} 0xA yes
5.10.1 yes BEGIN{die} 0xA no
5.10.1 no BEGIN{} 0 no
5.10.1 no BEGIN{die} 0 no
5.10.1 no BEGIN{} 0xA yes
5.10.1 no BEGIN{die} 0xA no
5.13.7 yes BEGIN{} 0 no
5.13.7 yes BEGIN{die} 0 no
5.13.7 yes BEGIN{} 0xA yes
5.13.7 yes BEGIN{die} 0xA yes
5.13.7 no BEGIN{} 0 no
5.13.7 no BEGIN{die} 0 yes
5.13.7 no BEGIN{} 0xA yes
5.13.7 no BEGIN{die} 0xA yes
Notice that, for non-threaded builds, BEGIN{die} goes from never sav-
ing the text to always saving it.
The commit in question is:
commit
f9bddea7d2a0d824366014c8ee6ba57e7dedd8c3
Author: Nicholas Clark <nick@ccl4.org>
Date: Tue Dec 2 20:43:58 2008 +0000
Implement PERLDBf_SAVESRC_INVALID, which saves source lines for string
evals that fail to compile.
p4raw-id: //depot/perl@34985
It stops unconditionally using the scoping mechanism to delete
$::{"_<(eval $num)"} on compilation failure:
- safestr = savepvn(tmpbuf, len);
- SAVEDELETE(PL_defstash, safestr, len);
but instead does it explicitly in this block:
+ if (doeval(gimme, NULL, runcv, seq)) {
+ if (was != PL_breakable_sub_gen /* Some subs defined here. */
+ ? (PERLDB_LINE || PERLDB_SAVESRC)
+ : PERLDB_SAVESRC_NOSUBS) {
+ /* Retain the filegv we created. */
+ } else {
+ char *const safestr = savepvn(tmpbuf, len);
+ SAVEDELETE(PL_defstash, safestr, len);
+ }
+ return DOCATCH(PL_eval_start);
+ } else {
+ /* We have already left the scope set up earler thanks to the LEAVE
+ in doeval(). */
+ if (PERLDB_SAVESRC_INVALID) {
+ /* Retain the filegv we created. */
+ } else {
+ (void)hv_delete(PL_defstash, tmpbuf, len, G_DISCARD);
+ }
+ return PL_op->op_next;
+ }
In the case of BEGIN{die}, that doeval() never returns, so the
clean-up code is not reached.
S_doeval never returns because call_list calls Perl_croak if it
catches a BEGIN error (appending the extra ‘BEGIN failed--compilation
aborted’, etc.). That takes execution all the way back to perl_run, so
it bypasses the clean-up code in pp_entereval.
What’s leaking is the GV created earlier in pp_entereval by this line:
CopFILE_set(&PL_compiling, tmpbuf+2);
CopFILE_set simply stores a string under threads, but creates a GV
under non-threaded builds.
This commit solves the problem by scheduling a deletion *before* call-
ing doeval, if the source lines have not been saved.
This works because the usual code to handle it is only bypassed when
there is a BEGIN block (a subroutine), so PL_breakable_sub_gen will
have gone up. So we never need to delete the saved lines when that
code is bypassed.