summaryrefslogtreecommitdiff
path: root/pp_hot.c
diff options
context:
space:
mode:
authorNicholas Clark <nick@ccl4.org>2011-08-29 15:25:23 +0200
committerNicholas Clark <nick@ccl4.org>2011-08-29 16:01:38 +0200
commit0c1438a1f54e0a813029e14b554e904c360b046a (patch)
tree4f9b8763d4792c0d34f9fc52c11d06c2cdcd207d /pp_hot.c
parentb1e878f6dbf2d7092691a3ba0fc5d369ae48aa8c (diff)
downloadperl-0c1438a1f54e0a813029e14b554e904c360b046a.tar.gz
For s///r, don't call SvPV_force() on the original value. Resolves #97954.
8ca8a454f60a417f optimised the implementation of s///r by avoiding an unconditional copy of the original value. However, it introduced a behaviour regression where if original value happened to be one of a few particular types, it could be modified by being forced to a string using SvPV_force(). The substitution was (correctly) performed on a copy of this string.
Diffstat (limited to 'pp_hot.c')
-rw-r--r--pp_hot.c8
1 files changed, 8 insertions, 0 deletions
diff --git a/pp_hot.c b/pp_hot.c
index 6abbf19c8e..758d334e62 100644
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -2294,6 +2294,14 @@ PP(pp_subst)
else {
if (force_on_match) {
force_on_match = 0;
+ if (rpm->op_pmflags & PMf_NONDESTRUCT) {
+ /* I feel that it should be possible to avoid this mortal copy
+ given that the code below copies into a new destination.
+ However, I suspect it isn't worth the complexity of
+ unravelling the C<goto force_it> for the small number of
+ cases where it would be viable to drop into the copy code. */
+ TARG = sv_2mortal(newSVsv(TARG));
+ }
s = SvPV_force(TARG, len);
goto force_it;
}