diff options
author | Father Chrysostomos <sprout@cpan.org> | 2012-12-10 05:43:41 -0800 |
---|---|---|
committer | Father Chrysostomos <sprout@cpan.org> | 2012-12-11 08:59:42 -0800 |
commit | 632b9d6f6a19a87ee168ebb81494b7df13c2eeb0 (patch) | |
tree | 3e38ee3efe01d8efd0a51d300aea8deb646ed1f3 /pp_hot.c | |
parent | 88e2091baeacd9a40eab4dac8601e88b3797e385 (diff) | |
download | perl-632b9d6f6a19a87ee168ebb81494b7df13c2eeb0.tar.gz |
pp_hot.c:pp_aassign: mortalise variable only if we have to
This affects the hash-assignment path.
Don’t mortalise the value to protect it from a magical key making the
hv_store_ent call die, as that could unduly extend the mortals stack.
Instead, copy the key if it is magical.
Based on a patch by Ruslan Zakirov.
Diffstat (limited to 'pp_hot.c')
-rw-r--r-- | pp_hot.c | 18 |
1 files changed, 14 insertions, 4 deletions
@@ -1096,10 +1096,18 @@ PP(pp_aassign) while (relem < lastrelem+odd) { /* gobble up all the rest */ HE *didstore; assert(*relem); - sv = lval ? sv_mortalcopy(*relem) : *relem; + /* Copy the key if aassign is called in lvalue context, + to avoid having the next op modify our rhs. Copy + it also if it is gmagical, lest it make the + hv_store_ent call below croak, leaking the value. */ + sv = lval || SvGMAGICAL(*relem) + ? sv_mortalcopy(*relem) + : *relem; relem++; assert(*relem); - tmpstr = sv_mortalcopy( *relem++ ); /* value */ + SvGETMAGIC(*relem); + tmpstr = newSV(0); + sv_setsv_nomg(tmpstr,*relem++); /* value */ if (gimme == G_ARRAY) { if (hv_exists_ent(hash, sv, 0)) /* key overwrites an existing entry */ @@ -1112,8 +1120,10 @@ PP(pp_aassign) } } didstore = hv_store_ent(hash,sv,tmpstr,0); - if (didstore) SvREFCNT_inc_simple_void_NN(tmpstr); - if (magic) SvSETMAGIC(tmpstr); + if (magic) { + if (!didstore) sv_2mortal(tmpstr); + SvSETMAGIC(tmpstr); + } TAINT_NOT; } LEAVE; |