summaryrefslogtreecommitdiff
path: root/sv.c
diff options
context:
space:
mode:
authorYves Orton <demerphq@gmail.com>2022-12-03 01:37:46 +0100
committerYves Orton <demerphq@gmail.com>2022-12-06 14:18:00 +0100
commit44282561d32a069322c5641afa41adf8fd82b77e (patch)
treeba482b15b66974f7e0251e07b9fc1bb4a23239bb /sv.c
parent9a266c095272ba2b07c7d46e33fa7b547628bcce (diff)
downloadperl-44282561d32a069322c5641afa41adf8fd82b77e.tar.gz
sv.c - sv_2pv_flags: Fix double FETCH from tied overloaded scalar
When dealing with a tied scalar with get magic, and the FETCH method returned a blessed reference with overloading magic (with "a" magic), the tied scalar returned from the fetch was not copied prior to calling the magic function as an argument, this would then cause the get magic to be called again if the overloaded method happened to copy or otherwise use the tied scalar. The solution is to copy the reference prior to dispatching the overload call. It looks like we have been testing for the double FETCH for some time, without any good rationale, so this test merely changes things to expect the desired count.
Diffstat (limited to 'sv.c')
-rw-r--r--sv.c13
1 files changed, 10 insertions, 3 deletions
diff --git a/sv.c b/sv.c
index 96283839f5..ca8992b49a 100644
--- a/sv.c
+++ b/sv.c
@@ -2830,21 +2830,28 @@ char *
Perl_sv_2pv_flags(pTHX_ SV *const sv, STRLEN *const lp, const U32 flags)
{
char *s;
+ bool done_gmagic = FALSE;
PERL_ARGS_ASSERT_SV_2PV_FLAGS;
assert (SvTYPE(sv) != SVt_PVAV && SvTYPE(sv) != SVt_PVHV
&& SvTYPE(sv) != SVt_PVFM);
- if (SvGMAGICAL(sv) && (flags & SV_GMAGIC))
+ if (SvGMAGICAL(sv) && (flags & SV_GMAGIC)) {
mg_get(sv);
+ done_gmagic = TRUE;
+ }
+
if (SvROK(sv)) {
if (SvAMAGIC(sv)) {
SV *tmpstr;
+ SV *nsv= (SV *)sv;
if (flags & SV_SKIP_OVERLOAD)
return NULL;
- tmpstr = AMG_CALLunary(sv, string_amg);
+ if (done_gmagic)
+ nsv = sv_mortalcopy_flags(sv,0);
+ tmpstr = AMG_CALLunary(nsv, string_amg);
TAINT_IF(tmpstr && SvTAINTED(tmpstr));
- if (tmpstr && (!SvROK(tmpstr) || (SvRV(tmpstr) != SvRV(sv)))) {
+ if (tmpstr && (!SvROK(tmpstr) || (SvRV(tmpstr) != SvRV(nsv)))) {
/* Unwrap this: */
/* char *pv = lp ? SvPV(tmpstr, *lp) : SvPV_nolen(tmpstr);
*/