summaryrefslogtreecommitdiff
path: root/dump.c
diff options
context:
space:
mode:
authorDavid Mitchell <davem@iabyn.com>2017-06-13 09:11:13 +0100
committerDavid Mitchell <davem@iabyn.com>2017-06-24 09:38:14 +0100
commit87058c31e9fa350bda8d797127c9c175d0b1a893 (patch)
treea30a1b8e831b83950e5a4a7a6b64bec517b1455a /dump.c
parent23c687d9d091a545afb2b769447c17fba98ba87a (diff)
downloadperl-87058c31e9fa350bda8d797127c9c175d0b1a893.tar.gz
add PL_curstackinfo->si_stack_hwm
On debugging builds only, add a mechanism for checking pp function calls for insufficient stack extending. It works by: * make the runops loop set a high-water-mark (HWM) variable equal to PL_stack_sp just before calling each pp function; * make EXTEND() etc update this HWM; * on return from the pp function, panic if PL_stack_sp is > HWM. This detects whether pp functions are pushing more items onto the stack than they are requesting space for. There's a possibility of false positives if the code is doing weird stuff like direct manipulation of stacks via PL_curstack, SWITCHSTACK() etc. It's also possible that one pp function "knows" that a previous pp function will have already grown the stack enough. Currently the only place in core that seems to do this is pp_enteriter, which allocates 1 stack slot so that pp_iter doesn't have to check each time it returns &PL_sv_yes/no. To accommodate this, the new macro EXTEND_SKIP() has been added, that tells perl that it's safely skipping an EXTEND() here.
Diffstat (limited to 'dump.c')
-rw-r--r--dump.c19
1 files changed, 18 insertions, 1 deletions
diff --git a/dump.c b/dump.c
index 7cdebfe875..b95092956f 100644
--- a/dump.c
+++ b/dump.c
@@ -2413,16 +2413,30 @@ Perl_sv_dump(pTHX_ SV *sv)
int
Perl_runops_debug(pTHX)
{
+#ifdef DEBUGGING && !defined DEBUGGING_RE_ONLY
+ SSize_t orig_stack_hwm = PL_curstackinfo->si_stack_hwm;
+
+ PL_curstackinfo->si_stack_hwm = PL_stack_sp - PL_stack_base;
+#endif
+
if (!PL_op) {
Perl_ck_warner_d(aTHX_ packWARN(WARN_DEBUGGING), "NULL OP IN RUN");
return 0;
}
-
DEBUG_l(Perl_deb(aTHX_ "Entering new RUNOPS level\n"));
do {
#ifdef PERL_TRACE_OPS
++PL_op_exec_cnt[PL_op->op_type];
#endif
+#ifdef DEBUGGING && !defined DEBUGGING_RE_ONLY
+ if (PL_curstackinfo->si_stack_hwm < PL_stack_sp - PL_stack_base)
+ Perl_croak_nocontext(
+ "panic: previous op failed to extend arg stack: "
+ "base=%p, sp=%p, hwm=%p\n",
+ PL_stack_base, PL_stack_sp,
+ PL_stack_base + PL_curstackinfo->si_stack_hwm);
+ PL_curstackinfo->si_stack_hwm = PL_stack_sp - PL_stack_base;
+#endif
if (PL_debug) {
ENTER;
SAVETMPS;
@@ -2452,6 +2466,9 @@ Perl_runops_debug(pTHX)
DEBUG_l(Perl_deb(aTHX_ "leaving RUNOPS level\n"));
PERL_ASYNC_CHECK();
+#ifdef DEBUGGING && !defined DEBUGGING_RE_ONLY
+ PL_curstackinfo->si_stack_hwm = orig_stack_hwm;
+#endif
TAINT_NOT;
return 0;
}