summaryrefslogtreecommitdiff
path: root/cop.h
diff options
context:
space:
mode:
authorFather Chrysostomos <sprout@cpan.org>2013-08-26 23:21:26 -0700
committerFather Chrysostomos <sprout@cpan.org>2013-08-27 00:13:07 -0700
commit25375124d2a06f2525e94c98c36eea007026778e (patch)
tree1fb76629bd05b31c30dfcda892fbbfcd4288f17b /cop.h
parent31d073689e2b5fa63aa7d4f8aaf529f75eeb5d0e (diff)
downloadperl-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.h16
1 files changed, 11 insertions, 5 deletions
diff --git a/cop.h b/cop.h
index 4376e62891..0741d92c14 100644
--- a/cop.h
+++ b/cop.h
@@ -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 {