summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pp_sys.c22
-rw-r--r--t/op/tie.t32
2 files changed, 52 insertions, 2 deletions
diff --git a/pp_sys.c b/pp_sys.c
index 106a44391b..6ef266fcde 100644
--- a/pp_sys.c
+++ b/pp_sys.c
@@ -511,6 +511,9 @@ OP *
Perl_tied_method(pTHX_ const char *const methname, SV **sp, SV *const sv,
const MAGIC *const mg, const U32 flags, U32 argc, ...)
{
+ SV **orig_sp = sp;
+ I32 ret_args;
+
PERL_ARGS_ASSERT_TIED_METHOD;
/* Ensure that our flag bits do not overlap. */
@@ -518,10 +521,15 @@ Perl_tied_method(pTHX_ const char *const methname, SV **sp, SV *const sv,
assert((TIED_METHOD_ARGUMENTS_ON_STACK & G_WANT) == 0);
assert((TIED_METHOD_SAY & G_WANT) == 0);
+ PUTBACK; /* sp is at *foot* of args, so this pops args from old stack */
+ PUSHSTACKi(PERLSI_MAGIC);
+ EXTEND(SP, argc+1); /* object + args */
PUSHMARK(sp);
PUSHs(SvTIED_obj(sv, mg));
- if (flags & TIED_METHOD_ARGUMENTS_ON_STACK)
+ if (flags & TIED_METHOD_ARGUMENTS_ON_STACK) {
+ Copy(orig_sp + 2, sp + 1, argc, SV*); /* copy args to new stack */
sp += argc;
+ }
else if (argc) {
const U32 mortalize_not_needed
= flags & TIED_METHOD_MORTALIZE_NOT_NEEDED;
@@ -544,7 +552,17 @@ Perl_tied_method(pTHX_ const char *const methname, SV **sp, SV *const sv,
SAVEGENERICSV(PL_ors_sv);
PL_ors_sv = newSVpvs("\n");
}
- call_method(methname, flags & G_WANT);
+ ret_args = call_method(methname, flags & G_WANT);
+ SPAGAIN;
+ orig_sp = sp;
+ POPSTACK;
+ SPAGAIN;
+ if (ret_args) { /* copy results back to original stack */
+ EXTEND(sp, ret_args);
+ Copy(orig_sp - ret_args + 1, sp + 1, ret_args, SV*);
+ sp += ret_args;
+ PUTBACK;
+ }
LEAVE_with_name("call_tied_method");
return NORMAL;
}
diff --git a/t/op/tie.t b/t/op/tie.t
index a4f969ad27..081379128f 100644
--- a/t/op/tie.t
+++ b/t/op/tie.t
@@ -1040,3 +1040,35 @@ TIEHANDLE
TIESCALAR
ok 1
ok 2
+########
+
+# RT #8611 mustn't goto outside the magic stack
+sub TIESCALAR { warn "tiescalar\n"; bless [] }
+sub FETCH { warn "fetch()\n"; goto FOO; }
+tie $f, "";
+warn "before fetch\n";
+my $a = "$f";
+warn "before FOO\n";
+FOO:
+warn "after FOO\n";
+EXPECT
+tiescalar
+before fetch
+fetch()
+Can't find label FOO at - line 4.
+########
+
+# RT #8611 mustn't goto outside the magic stack
+sub TIEHANDLE { warn "tiehandle\n"; bless [] }
+sub PRINT { warn "print()\n"; goto FOO; }
+tie *F, "";
+warn "before print\n";
+print F "abc";
+warn "before FOO\n";
+FOO:
+warn "after FOO\n";
+EXPECT
+tiehandle
+before print
+print()
+Can't find label FOO at - line 4.