This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Perl_sv_vcatpvfn_flags: make %n missing arg fatal
authorDavid Mitchell <davem@iabyn.com>
Wed, 24 May 2017 15:09:25 +0000 (16:09 +0100)
committerDavid Mitchell <davem@iabyn.com>
Wed, 7 Jun 2017 08:11:03 +0000 (09:11 +0100)
Normally sprintf et al just warn if there aren't enough args; but since %n
wants to write the current string length to the next arg, make it fatal.

Formerly it would croak anyway, but with a spurious "Modification of a
read-only value" error as it as it tried to set &PL_sv_no

pod/perldiag.pod
sv.c
t/op/sprintf2.t

index 60f32ec..cf9801e 100644 (file)
@@ -3527,6 +3527,11 @@ ended earlier on the current line.
 (W syntax) An underscore (underbar) in a numeric constant did not
 separate two digits.
 
+=item Missing argument for %n in %s
+
+(F) A C<%n> was used in a format string with no corresponding argument for
+perl to write the current string length to.
+
 =item Missing argument in %s
 
 (W missing) You called a function with fewer arguments than other
diff --git a/sv.c b/sv.c
index 489cbea..5fc3b89 100644 (file)
--- a/sv.c
+++ b/sv.c
@@ -13035,8 +13035,13 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p
 #endif
                     }
                 }
-                else
+                else {
+                    if (arg_missing)
+                        Perl_croak_nocontext(
+                            "Missing argument for %%n in %s",
+                                PL_op ? OP_DESC(PL_op) : "sv_vcatpvfn()");
                     sv_setuv_mg(argsv, has_utf8 ? (UV)sv_len_utf8(sv) : (UV)i);
+                }
                 goto donevalidconversion;
             }
 
index adbcc7b..b2d0c48 100644 (file)
@@ -295,14 +295,6 @@ for my $i (1, 3, 5, 10) {
        "width & precision interplay with utf8 strings, length=$i");
 }
 
-# Used to mangle PL_sv_undef
-fresh_perl_like(
-    'print sprintf "xxx%n\n"; print undef',
-    qr/Modification of a read-only value attempted at\b/,
-    { switches => [ '-w' ] },
-    q(%n should not be able to modify read-only constants),
-);
-
 # check overflows
 for (int(~0/2+1), ~0, "9999999999999999999") {
     is(eval {sprintf "%${_}d", 0}, undef, "no sprintf result expected %${_}d");
@@ -971,5 +963,12 @@ SKIP: {
     ok(!utf8::is_utf8($s), "first arg not special utf8-wise");
 }
 
+# sprintf("%n") used to croak "Modification of a read-only value"
+# as it tried to set &PL_sv_no
+
+{
+    eval { my $s = sprintf("%n"); };
+    like $@, qr/Missing argument for %n in sprintf/, "%n";
+}
 
 done_testing();