When strptime() receives a reference, ensure it's a mutable scalar
authorPaul "LeoNerd" Evans <leonerd@leonerd.org.uk>
Wed, 1 Feb 2012 19:37:34 +0000 (19:37 +0000)
committerÆvar Arnfjörð Bjarmason <avar@cpan.org>
Sat, 11 Feb 2012 22:22:25 +0000 (22:22 +0000)
ext/POSIX/POSIX.xs
ext/POSIX/t/time.t

index 64fe3fb..2250f03 100644 (file)
@@ -1876,9 +1876,12 @@ strptime(str, fmt, sec=-1, min=-1, hour=-1, mday=-1, mon=-1, year=-1, wday=-1, y
            tm.tm_yday = yday;
            tm.tm_isdst = isdst;
 
-           if(SvROK(str)) {
+           if(SvROK(str) && !SvOBJECT(SvRV(str))) {
                strref = SvRV(str);
 
+               if(SvTYPE(strref) > SVt_PVMG || SvREADONLY(strref))
+                   croak("str is not a reference to a mutable scalar");
+
                str_base = str_c = SvPV_nolen(strref);
 
                if(SvTYPE(strref) >= SVt_PVMG && SvMAGIC(strref))
@@ -1887,6 +1890,9 @@ strptime(str, fmt, sec=-1, min=-1, hour=-1, mday=-1, mon=-1, year=-1, wday=-1, y
                if(posmg)
                    str_c += posmg->mg_len;
            }
+           else if(SvROK(str) && SvTYPE(SvRV(str)) == SVt_REGEXP) {
+               croak("str is not a reference to a mutable scalar");
+           }
            else {
                str_c = SvPV_nolen(str);
            }
index bbf2c50..959f675 100644 (file)
@@ -4,7 +4,7 @@ use strict;
 
 use Config;
 use POSIX;
-use Test::More tests => 29;
+use Test::More tests => 33;
 
 # go to UTC to avoid DST issues around the world when testing.  SUS3 says that
 # null should get you UTC, but some environments want the explicit names.
@@ -98,6 +98,24 @@ pos($str) = 10;
 is_deeply(\@time, [0, 0, 0, 1, 12-1, 2012-1900, 6, 335, 0], 'strptime() starts SCALAR ref at pos()');
 is(pos($str), 20, 'strptime() updates pos() magic on SCALAR ref');
 
+eval { POSIX::strptime({}, "format") };
+like($@, qr/not a reference to a mutable scalar/, 'strptime() dies on HASH ref');
+
+eval { POSIX::strptime(\"boo", "format") };
+like($@, qr/not a reference to a mutable scalar/, 'strptime() dies on const literal ref');
+
+eval { POSIX::strptime(qr/boo!/, "format") };
+like($@, qr/not a reference to a mutable scalar/, 'strptime() dies on Regexp');
+
+$str = bless [], "WithStringOverload";
+{
+   package WithStringOverload;
+   use overload '""' => sub { return "2012-02-01" };
+}
+
+@time = POSIX::strptime($str, "%Y-%m-%d", 0, 0, 0);
+is_deeply(\@time, [0, 0, 0, 1, 2-1, 2012-1900, 3, 31, 0], 'strptime() allows object with string overload');
+
 setlocale(LC_TIME, $orig_loc) || die "Cannot setlocale() back to orig: $!";
 
 # clock() seems to have different definitions of what it does between POSIX