Subject: | Existing stacks are not protected against reallocation. |
pp_leavesub does this:
POPSUB(cx,sv);
before this:
return cx->blk_sub.retop;
Since POPSUB does LEAVE_SCOPE, it may call a destructor registered by
establish_cleanup. That destructor will call run_cleanup, which does
call_sv, which indirectly calls pp_entersub, which does PUSHBLOCK,
which does CXINC, which may reallocate the context stack.
So cx in the outer pp_leavesub call may end up pointing to freed-and-
reused memory by the time the ‘return cx->blk_sub.retop’ is reached.
I discovered this when working on PERL_DEBUG_READONLY_COW.
ext/XS-APItest/t/cleanup.t was failing. In this case, the former con-
text stack had been reused for some freshly allocated and zeroed mem-
ory, so pp_leavesub returned NULL, causing the program to exit.
I am about to extend STRESS_REALLOC in the perl core to force a
reallocation in Perl_cxinc (as I did with the argument stack in
865e3ae09). This causes ext/XS-APItest/t/cleanup.t to fail under
-DPERL_POISON + -DSTRESS_REALLOC + threads, which was the intent. So
I am updating XS::APItest to account, like this:
diff --git a/ext/XS-APItest/APItest.xs b/ext/XS-APItest/APItest.xs
index a4b91f6..4234469 100644
--- a/ext/XS-APItest/APItest.xs
+++ b/ext/XS-APItest/APItest.xs
@@ -533,12 +533,14 @@ STATIC void
THX_run_cleanup(pTHX_ void *cleanup_code_ref)
{
dSP;
+ PUSHSTACK;
ENTER;
SAVETMPS;
PUSHMARK(SP);
call_sv((SV*)cleanup_code_ref, G_VOID|G_DISCARD);
FREETMPS;
LEAVE;
+ POPSTACK;
}
(The commit, on the sprout/realloc branch, won’t land in blead for a
while, because POISON + STRESS_REALLOC is a very slow combination. I
left it running overnight, and it is still compiling Encode and run-
ning mktables.)
I imagine Scope::Cleanup will fail under that configuration, too
(since it has the same code), but I have not tested it.