New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
\substr reuses lvalues (sometimes) #6306
Comments
From @jbenjoreCreated by josh@lavendergreens.orgThe following code prints "abbb" when it should be "abab". BrowserUK $s = "ab"; $r[$_] = \ substr $s, $_, 1 for (0, 1); Perl Info
|
From @eserte"Joshua b.Jore (via RT)" <perlbug-followup@perl.org> writes:
The patch below fixes the problem. The fix is not very elegant, Inline Patch--- bleedperl/pp.c Sun Feb 2 18:59:19 2003
+++ bleedperl2/pp.c Fri Feb 14 11:13:40 2003
@@ -476,6 +476,17 @@ S_refto(pTHX_ SV *sv)
}
else if (SvPADTMP(sv) && !IS_PADGV(sv))
sv = newSVsv(sv);
+ else if (SvTYPE(sv) == SVt_PVLV && LvTYPE(sv) == 'x') {
+ /* [perl #20933] */
+ SV* new_sv = newSVsv(sv);
+ sv_upgrade(new_sv, SVt_PVLV);
+ sv_magic(new_sv, Nullsv, PERL_MAGIC_substr, Nullch, 0);
+ LvTYPE(new_sv) = 'x';
+ LvTARG(new_sv) = SvREFCNT_inc(LvTARG(sv));
+ LvTARGOFF(new_sv) = LvTARGOFF(sv);
+ LvTARGLEN(new_sv) = LvTARGLEN(sv);
+ sv = new_sv;
+ }
else {
SvTEMP_off(sv);
(void)SvREFCNT_inc(sv);
--- bleedperl/t/op/substr.t Wed Mar 21 02:18:37 2001
+++ bleedperl2/t/op/substr.t Fri Feb 14 09:53:01 2003
@@ -1,6 +1,6 @@
#!./perl
-print "1..174\n";
+print "1..175\n";
#P = start of string Q = start of substr R = end of substr S = end of string
@@ -585,3 +585,10 @@ ok 173, $x eq "\xFFb\x{100}\x{200}";
substr($x = "\x{100}\x{200}", 2, 0, "\xFFb");
ok 174, $x eq "\x{100}\x{200}\xFFb";
+# [perl #20933]
+{
+ my $s = "ab";
+ my @r;
+ $r[$_] = \ substr $s, $_, 1 for (0, 1);
+ ok 175, join("", map { $$_ } @r) eq "ab";
+}
-- tktimex - project time manager |
From @iabynOn Fri, Feb 14, 2003 at 12:14:57PM +0100, Slaven Rezic wrote:
You will need a similar fix for vec (LvTYPE == 'v') too. Perhaps an alternative approach would be for substr and vec in an lvalue -- |
From @eserteDave Mitchell <davem@fdgroup.com> writes:
Below is a revised patch.
Inline Patch--- bleedperl/pp.c Sun Feb 2 18:59:19 2003
+++ bleedperl2/pp.c Fri Feb 14 19:40:10 2003
@@ -476,6 +476,19 @@ S_refto(pTHX_ SV *sv)
}
else if (SvPADTMP(sv) && !IS_PADGV(sv))
sv = newSVsv(sv);
+ else if (SvTYPE(sv) == SVt_PVLV && (LvTYPE(sv) == 'x' || LvTYPE(sv) == 'v')) {
+ /* [perl #20933] */
+ SV* new_sv = newSVsv(sv);
+ sv_upgrade(new_sv, SVt_PVLV);
+ sv_magic(new_sv, Nullsv,
+ (LvTYPE(sv) == 'x' ? PERL_MAGIC_substr : PERL_MAGIC_vec),
+ Nullch, 0);
+ LvTYPE(new_sv) = LvTYPE(sv);
+ LvTARG(new_sv) = SvREFCNT_inc(LvTARG(sv));
+ LvTARGOFF(new_sv) = LvTARGOFF(sv);
+ LvTARGLEN(new_sv) = LvTARGLEN(sv);
+ sv = new_sv;
+ }
else {
SvTEMP_off(sv);
(void)SvREFCNT_inc(sv);
--- bleedperl/t/op/substr.t Wed Mar 21 02:18:37 2001
+++ bleedperl2/t/op/substr.t Fri Feb 14 09:53:01 2003
@@ -1,6 +1,6 @@
#!./perl
-print "1..174\n";
+print "1..175\n";
#P = start of string Q = start of substr R = end of substr S = end of string
@@ -585,3 +585,10 @@ ok 173, $x eq "\xFFb\x{100}\x{200}";
substr($x = "\x{100}\x{200}", 2, 0, "\xFFb");
ok 174, $x eq "\x{100}\x{200}\xFFb";
+# [perl #20933]
+{
+ my $s = "ab";
+ my @r;
+ $r[$_] = \ substr $s, $_, 1 for (0, 1);
+ ok 175, join("", map { $$_ } @r) eq "ab";
+}
--- bleedperl/t/op/vec.t Wed Feb 27 01:56:06 2002
+++ bleedperl2/t/op/vec.t Fri Feb 14 19:40:34 2003
@@ -1,6 +1,6 @@
#!./perl
-print "1..30\n";
+print "1..31\n";
my $Is_EBCDIC = (ord('A') == 193) ? 1 : 0;
@@ -86,3 +86,14 @@ print "ok 29\n";
vec(substr($foo, 1,3), 5, 4) = 3;
print "not " if $foo ne "\x61\x62\x63\x34\x65\x66";
print "ok 30\n";
+
+# A variation of [perl #20933]
+{
+ my $s = "";
+ vec($s, 0, 1) = 0;
+ vec($s, 1, 1) = 1;
+ my @r;
+ $r[$_] = \ vec $s, $_, 1 for (0, 1);
+ print "not " if (${ $r[0] } != 0 || ${ $r[1] } != 1);
+ print "ok 31\n";
+}
-- Slaven Rezic - slaven@rezic.de |
From @iabynOn Fri, Feb 14, 2003 at 08:23:20PM +0100, Slaven Rezic wrote:
How about the following alternative? Rather than adding code the Dave. Inline Patch--- pp.c- Fri Feb 14 22:51:50 2003
+++ pp.c Fri Feb 14 22:36:12 2003
@@ -3094,6 +3094,8 @@ PP(pp_substr)
sv_setpvn(sv,"",0); /* avoid lexical reincarnation */
}
+ if (SvREFCNT(TARG) > 1) /* don't share the TARG (#20933) */
+ TARG = sv_newmortal();
if (SvTYPE(TARG) < SVt_PVLV) {
sv_upgrade(TARG, SVt_PVLV);
sv_magic(TARG, Nullsv, PERL_MAGIC_substr, Nullch, 0);
@@ -3124,6 +3126,8 @@ PP(pp_vec)
SvTAINTED_off(TARG); /* decontaminate */
if (lvalue) { /* it's an lvalue! */
+ if (SvREFCNT(TARG) > 1) /* don't share the TARG (#20933) */
+ TARG = sv_newmortal();
if (SvTYPE(TARG) < SVt_PVLV) {
sv_upgrade(TARG, SVt_PVLV);
sv_magic(TARG, Nullsv, PERL_MAGIC_vec, Nullch, 0); |
From @eserteDave Mitchell <davem@fdgroup.com> writes:
Yes, this looks much cleaner to me. Regards,
-- Berlin Perl Mongers - http://berliner.pm.org |
@iabyn - Status changed from 'new' to 'resolved' |
Migrated from rt.perl.org#20933 (status was 'resolved')
Searchable as RT20933$
The text was updated successfully, but these errors were encountered: