[perl #29070] Add vstring set-magic
authorFather Chrysostomos <sprout@cpan.org>
Fri, 23 Dec 2011 22:18:16 +0000 (14:18 -0800)
committerFather Chrysostomos <sprout@cpan.org>
Fri, 23 Dec 2011 22:45:55 +0000 (14:45 -0800)
Some operators, like pp_complement, assign their argument to TARG
(which copies vstring magic), modify it in place, and then call set-
magic.  That’s supposed to work, but vstring magic was remaining as it
was, such that ~v7 would still be treated as "v7" by vstring-aware
code, even though the resulting string is not "\7".

This commit adds vstring set-magic that checks to see whether the pv
still matches the vstring.  It cannot simply free the vstring magic,
as that would prevent $x=v0 from working.

embed.fnc
embed.h
mg.c
mg_raw.h
mg_vtable.h
proto.h
regen/mg_vtable.pl
t/op/bop.t

index 3b81d3f..22886ed 100644 (file)
--- a/embed.fnc
+++ b/embed.fnc
@@ -763,6 +763,7 @@ p   |int    |magic_settaint |NN SV* sv|NN MAGIC* mg
 p      |int    |magic_setuvar  |NN SV* sv|NN MAGIC* mg
 p      |int    |magic_setvec   |NN SV* sv|NN MAGIC* mg
 p      |int    |magic_setutf8  |NN SV* sv|NN MAGIC* mg
+p      |int    |magic_setvstring|NN SV* sv|NN MAGIC* mg
 p      |int    |magic_set_all_env|NN SV* sv|NN MAGIC* mg
 p      |U32    |magic_sizepack |NN SV* sv|NN MAGIC* mg
 p      |int    |magic_wipepack |NN SV* sv|NN MAGIC* mg
diff --git a/embed.h b/embed.h
index 86ffcd4..662c933 100644 (file)
--- a/embed.h
+++ b/embed.h
 #define magic_setutf8(a,b)     Perl_magic_setutf8(aTHX_ a,b)
 #define magic_setuvar(a,b)     Perl_magic_setuvar(aTHX_ a,b)
 #define magic_setvec(a,b)      Perl_magic_setvec(aTHX_ a,b)
+#define magic_setvstring(a,b)  Perl_magic_setvstring(aTHX_ a,b)
 #define magic_sizepack(a,b)    Perl_magic_sizepack(aTHX_ a,b)
 #define magic_wipepack(a,b)    Perl_magic_wipepack(aTHX_ a,b)
 #define mg_localize(a,b,c)     Perl_mg_localize(aTHX_ a,b,c)
diff --git a/mg.c b/mg.c
index 3432dfe..31330dd 100644 (file)
--- a/mg.c
+++ b/mg.c
@@ -2294,6 +2294,19 @@ Perl_magic_setvec(pTHX_ SV *sv, MAGIC *mg)
     return 0;
 }
 
+int
+Perl_magic_setvstring(pTHX_ SV *sv, MAGIC *mg)
+{
+    PERL_ARGS_ASSERT_MAGIC_SETVSTRING;
+
+    if (SvPOKp(sv)) {
+       SV * const vecsv = sv_newmortal();
+       scan_vstring(mg->mg_ptr, mg->mg_ptr + mg->mg_len, vecsv);
+       if (sv_eq_flags(vecsv, sv, 0 /*nomg*/)) return 0;
+    }
+    return sv_unmagic(sv, mg->mg_type);
+}
+
 int
 Perl_magic_getdefelem(pTHX_ SV *sv, MAGIC *mg)
 {
index 7a45e6d..f4e1742 100644 (file)
--- a/mg_raw.h
+++ b/mg_raw.h
@@ -74,7 +74,7 @@
       "/* taint 't' Taintedness */" },
     { 'U', "want_vtbl_uvar",
       "/* uvar 'U' Available for use by extensions */" },
-    { 'V', "magic_vtable_max | PERL_MAGIC_VALUE_MAGIC",
+    { 'V', "want_vtbl_vstring | PERL_MAGIC_VALUE_MAGIC",
       "/* vstring 'V' SV was vstring literal */" },
     { 'v', "want_vtbl_vec | PERL_MAGIC_VALUE_MAGIC",
       "/* vec 'v' vec() lvalue */" },
index 2e3ca35..12f2fa3 100644 (file)
@@ -90,6 +90,7 @@ enum {                /* pass one of these to get_vtbl */
     want_vtbl_utf8,
     want_vtbl_uvar,
     want_vtbl_vec,
+    want_vtbl_vstring,
     magic_vtable_max
 };
 
@@ -124,7 +125,8 @@ EXTCONST char *PL_magic_vtable_names[magic_vtable_max] = {
     "taint",
     "utf8",
     "uvar",
-    "vec"
+    "vec",
+    "vstring"
 };
 #else
 EXTCONST char *PL_magic_vtable_names[magic_vtable_max];
@@ -186,7 +188,8 @@ EXT_MGVTBL PL_magic_vtables[magic_vtable_max] = {
   { Perl_magic_gettaint, Perl_magic_settaint, 0, 0, 0, 0, 0, 0 },
   { 0, Perl_magic_setutf8, 0, 0, 0, 0, 0, 0 },
   { Perl_magic_getuvar, Perl_magic_setuvar, 0, 0, 0, 0, 0, 0 },
-  { Perl_magic_getvec, Perl_magic_setvec, 0, 0, 0, 0, 0, 0 }
+  { Perl_magic_getvec, Perl_magic_setvec, 0, 0, 0, 0, 0, 0 },
+  { 0, Perl_magic_setvstring, 0, 0, 0, 0, 0, 0 }
 };
 #else
 EXT_MGVTBL PL_magic_vtables[magic_vtable_max];
@@ -227,5 +230,6 @@ EXT_MGVTBL PL_magic_vtables[magic_vtable_max];
 #define PL_vtbl_utf8 PL_magic_vtables[want_vtbl_utf8]
 #define PL_vtbl_uvar PL_magic_vtables[want_vtbl_uvar]
 #define PL_vtbl_vec PL_magic_vtables[want_vtbl_vec]
+#define PL_vtbl_vstring PL_magic_vtables[want_vtbl_vstring]
 
 /* ex: set ro: */
diff --git a/proto.h b/proto.h
index 60f191a..5184bff 100644 (file)
--- a/proto.h
+++ b/proto.h
@@ -2307,6 +2307,12 @@ PERL_CALLCONV int        Perl_magic_setvec(pTHX_ SV* sv, MAGIC* mg)
 #define PERL_ARGS_ASSERT_MAGIC_SETVEC  \
        assert(sv); assert(mg)
 
+PERL_CALLCONV int      Perl_magic_setvstring(pTHX_ SV* sv, MAGIC* mg)
+                       __attribute__nonnull__(pTHX_1)
+                       __attribute__nonnull__(pTHX_2);
+#define PERL_ARGS_ASSERT_MAGIC_SETVSTRING      \
+       assert(sv); assert(mg)
+
 PERL_CALLCONV U32      Perl_magic_sizepack(pTHX_ SV* sv, MAGIC* mg)
                        __attribute__nonnull__(pTHX_1)
                        __attribute__nonnull__(pTHX_2);
index 799be6b..3c3c484 100644 (file)
@@ -84,7 +84,7 @@ my %mg =
                    unknown_to_sv_magic => 1 },
      vec => { char => 'v', vtable => 'vec', value_magic => 1,
              desc => 'vec() lvalue' },
-     vstring => { char => 'V', value_magic => 1,
+     vstring => { char => 'V', value_magic => 1, vtable => 'vstring',
                  desc => 'SV was vstring literal' },
      utf8 => { char => 'w', vtable => 'utf8', value_magic => 1,
               desc => 'Cached UTF-8 information' },
@@ -144,6 +144,7 @@ my %sig =
                    cond => '#ifdef USE_LOCALE_COLLATE'},
      'hintselem' => {set => 'sethint', clear => 'clearhint'},
      'hints' => {clear => 'clearhints'},
+     'vstring' => {set => 'setvstring'},
 );
 
 my ($vt, $raw, $names) = map {
index 238d272..0f28f79 100644 (file)
@@ -15,7 +15,7 @@ BEGIN {
 # If you find tests are failing, please try adding names to tests to track
 # down where the failure is, and supply your new names as a patch.
 # (Just-in-time test naming)
-plan tests => 171 + (10*13*2) + 4;
+plan tests => 171 + (10*13*2) + 5;
 
 # numerics
 ok ((0xdead & 0xbeef) == 0x9ead);
@@ -554,3 +554,7 @@ $strval = "x";
 eval { $obj |= "Q" };
 $strval = "z";
 is("$obj", "z", "|= doesn't break string overload");
+
+# [perl #29070]
+$^A .= new version ~$_ for "\xce", v205, "\xcc";
+is $^A, "123", '~v0 clears vstring magic on retval';