diff options
author | Father Chrysostomos <sprout@cpan.org> | 2013-08-26 23:21:26 -0700 |
---|---|---|
committer | Father Chrysostomos <sprout@cpan.org> | 2013-08-27 00:13:07 -0700 |
commit | 25375124d2a06f2525e94c98c36eea007026778e (patch) | |
tree | 1fb76629bd05b31c30dfcda892fbbfcd4288f17b /cop.h | |
parent | 31d073689e2b5fa63aa7d4f8aaf529f75eeb5d0e (diff) | |
download | perl-25375124d2a06f2525e94c98c36eea007026778e.tar.gz |
[perl #119311] Keep CvDEPTH and savestack in sync
when unwinding sub and format calls.
The comments in the added test file explain what the problem is.
The fix is to call LEAVE_SCOPE in POPSUB and POPFORMAT (to free their
lexicals) before lowering CvDEPTH.
If the context has already been popped via cxstack_ix--, then
LEAVE_SCOPE could overwrite it, so accessing cx after LEAVE_SCOPE is
unsafe. Hence the changes to POPSUB and POPFORMAT are a bit involved.
Some callers of POPSUB do a temporary cxstack_ix++ first so they
can access cx afterwards. Two cases needed to be changed to
work that way.
Diffstat (limited to 'cop.h')
-rw-r--r-- | cop.h | 16 |
1 files changed, 11 insertions, 5 deletions
@@ -648,6 +648,7 @@ struct block_format { #define POPSUB(cx,sv) \ STMT_START { \ + const I32 olddepth = cx->blk_sub.olddepth; \ RETURN_PROBE(CvNAMED(cx->blk_sub.cv) \ ? HEK_KEY(CvNAME_HEK(cx->blk_sub.cv)) \ : GvENAME(CvGV(cx->blk_sub.cv)), \ @@ -671,7 +672,8 @@ struct block_format { } \ } \ sv = MUTABLE_SV(cx->blk_sub.cv); \ - if (sv && (CvDEPTH((const CV*)sv) = cx->blk_sub.olddepth)) \ + LEAVE_SCOPE(PL_scopestack[cx->blk_oldscopesp-1]); \ + if (sv && (CvDEPTH((const CV*)sv) = olddepth)) \ sv = NULL; \ } STMT_END @@ -681,11 +683,15 @@ struct block_format { } STMT_END #define POPFORMAT(cx) \ - setdefout(cx->blk_format.dfoutgv); \ - CvDEPTH(cx->blk_format.cv)--; \ - if (!CvDEPTH(cx->blk_format.cv)) \ + STMT_START { \ + CV * const cv = cx->blk_format.cv; \ + GV * const dfuot = cx->blk_format.dfoutgv; \ + setdefout(dfuot); \ + LEAVE_SCOPE(PL_scopestack[cx->blk_oldscopesp-1]); \ + if (!--CvDEPTH(cv)) \ SvREFCNT_dec_NN(cx->blk_format.cv); \ - SvREFCNT_dec_NN(cx->blk_format.dfoutgv); + SvREFCNT_dec_NN(dfuot); \ + } STMT_END /* eval context */ struct block_eval { |