summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Mitchell <davem@iabyn.com>2012-11-11 00:01:21 +0000
committerDavid Mitchell <davem@iabyn.com>2012-11-11 00:01:21 +0000
commit3d26b81e83dca7175e314b31d265a01e1e9b0320 (patch)
tree0353cf491729d1cb26db261c0ae9fd931dff5857
parent285c5e4279bd1c29a0fad0f195fb22a65ac33ab2 (diff)
downloadperl-3d26b81e83dca7175e314b31d265a01e1e9b0320.tar.gz
make MULTICALL safe across cxstack reallocs
[perl #115602] MUTLICALL sets a local var, cx, to point to the current context stack frame. When a function is called, the context stack might be realloc()ed, in which case cx would point to freed memory.
-rw-r--r--cop.h3
-rw-r--r--ext/XS-APItest/t/multicall.t15
2 files changed, 16 insertions, 2 deletions
diff --git a/cop.h b/cop.h
index 4c7b710595..74ec151a45 100644
--- a/cop.h
+++ b/cop.h
@@ -1217,7 +1217,8 @@ See L<perlcall/LIGHTWEIGHT CALLBACKS>.
#define POP_MULTICALL \
STMT_START { \
- if (! ((CvDEPTH(multicall_cv) = cx->blk_sub.olddepth)) ) { \
+ cx = &cxstack[cxstack_ix]; \
+ if (! ((CvDEPTH(multicall_cv) = cx->blk_sub.olddepth)) ) { \
LEAVESUB(multicall_cv); \
} \
POPBLOCK(cx,PL_curpm); \
diff --git a/ext/XS-APItest/t/multicall.t b/ext/XS-APItest/t/multicall.t
index 983f5fd016..f96f62e743 100644
--- a/ext/XS-APItest/t/multicall.t
+++ b/ext/XS-APItest/t/multicall.t
@@ -7,7 +7,7 @@
use warnings;
use strict;
-use Test::More tests => 6;
+use Test::More tests => 7;
use XS::APItest;
@@ -48,3 +48,16 @@ use XS::APItest;
is($destroyed, 1, "f now destroyed");
}
+
+# [perl #115602]
+# deep recursion realloced the CX stack, but the dMULTICALL local var
+# 'cx' still pointed to the old one.
+# Thius doesn;t actually test the failure (I couldn't think of a way to
+# get the failure to show at the perl level) but it allows valgribnd or
+# similar to spot any errors.
+
+{
+ sub rec { my $c = shift; rec($c-1) if $c > 0 };
+ my @r = XS::APItest::multicall_each { rec(90) } 1,2,3;
+ pass("recursion");
+}