summaryrefslogtreecommitdiff
path: root/gv.c
diff options
context:
space:
mode:
authorFather Chrysostomos <sprout@cpan.org>2011-04-07 23:02:35 -0700
committerFather Chrysostomos <sprout@cpan.org>2011-04-07 23:02:35 -0700
commit75ea7a126f0cb23a33771013529ef0e381ffe55d (patch)
tree66894839a7d3b81dd954fe71add39a3edf0de370 /gv.c
parent7d779b236fc2cb0c2dbe324bda777c76494a71a5 (diff)
downloadperl-75ea7a126f0cb23a33771013529ef0e381ffe55d.tar.gz
[perl #87708] Fix ‘$tied binop $tied’
The short story: In 5.13.1 or .2 these ops started calling get-magic just once if the same gmagical scalar was used for both operands. Then the same value would be used on both sides. In 5.12 FETCH would be called twice with both return values used, but they would be swapped in most cases (so $t/$t would return 1.5 if $t returned 2 and then 3). Now FETCH is called twice and the two operands are used in the right order. Up till now there have been patches to fix specific ops, but I real- ised that the same ten or so lines of code would have to be added to the rest of the 20+ pp_ functions, all of which use tryAMAGICbin_MG (which calls Perl_try_amagic_bin in gv.c), so it made sense to add the code to Perl_try_amagic_bin instead. This fixes all the ops in one fell swoop. The code in question checks whether the left and right operands are the same gmagical scalar. If so, it copies the scalar into a new mor- tal one, and then calls get-magic on the original operand to get its new value (for the rhs). The new scalar is placed just below the top of the stack, so it becomes the left operand. This does slow down the bitwise integer ops slightly, but only in this rare edge case. And the simplification of the code seems worth it. Forthcoming are commits that revert some of the changes already made, as this commit renders them unnecessary.
Diffstat (limited to 'gv.c')
-rw-r--r--gv.c16
1 files changed, 14 insertions, 2 deletions
diff --git a/gv.c b/gv.c
index b1bc60f4e6..2abe418519 100644
--- a/gv.c
+++ b/gv.c
@@ -2077,9 +2077,21 @@ Perl_try_amagic_bin(pTHX_ int method, int flags) {
return TRUE;
}
}
+ if(left==right && SvGMAGICAL(left)) {
+ SV * const left = sv_newmortal();
+ *(sp-1) = left;
+ /* Print the uninitialized warning now, so it includes the vari-
+ able name. */
+ if (!SvOK(right)) {
+ if (ckWARN(WARN_UNINITIALIZED)) report_uninit(right);
+ sv_setsv_flags(left, &PL_sv_no, 0);
+ }
+ else sv_setsv_flags(left, right, 0);
+ SvGETMAGIC(right);
+ }
if (flags & AMGf_numeric) {
- if (SvROK(left))
- *(sp-1) = sv_2num(left);
+ if (SvROK(TOPm1s))
+ *(sp-1) = sv_2num(TOPm1s);
if (SvROK(right))
*sp = sv_2num(right);
}