From: Christian Brabandt Date: Thu, 11 Dec 2025 19:51:03 +0000 (+0100) Subject: patch 9.1.1971: crash with invalid positional argument 0 in printf() X-Git-Tag: v9.1.1972~1 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=98a0cbf05bd45fa6c4ede7b791fd21760bc587c8;p=thirdparty%2Fvim.git patch 9.1.1971: crash with invalid positional argument 0 in printf() Problem: crash with invalid positional argument 0 in printf() Solution: Reject positional arguments <= 0. closes: #18898 Signed-off-by: Christian Brabandt --- diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt index 3ac3d8a33e..5b143cda8a 100644 --- a/runtime/doc/builtin.txt +++ b/runtime/doc/builtin.txt @@ -1,4 +1,4 @@ -*builtin.txt* For Vim version 9.1. Last change: 2025 Dec 10 +*builtin.txt* For Vim version 9.1. Last change: 2025 Dec 11 VIM REFERENCE MANUAL by Bram Moolenaar @@ -8336,24 +8336,24 @@ printf({fmt}, {expr1} ...) *printf()* *E1502* You can re-use a [field-width] (or [precision]) argument: > - echo printf("%1$d at width %2$d is: %01$*2$d", 1, 2) + echo printf("%1$d at width %2$d is: %1$0*2$d", 1, 2) < 1 at width 2 is: 01 However, you can't use it as a different type: > - echo printf("%1$d at width %2$ld is: %01$*2$d", 1, 2) + echo printf("%1$d at width %2$ld is: %1$0*2$d", 1, 2) < E1502: Positional argument 2 used as field width reused as different type: long int/int *E1503* When a positional argument is used, but not the correct number or arguments is given, an error is raised: > - echo printf("%1$d at width %2$d is: %01$*2$.*3$d", 1, 2) + echo printf("%1$d at width %2$d is: %1$0*2$.*3$d", 1, 2) < E1503: Positional argument 3 out of bounds: %1$d at width - %2$d is: %01$*2$.*3$d + %2$d is: %1$0*2$.*3$d Only the first error is reported: > - echo printf("%01$*2$.*3$d %4$d", 1, 2) -< E1503: Positional argument 3 out of bounds: %01$*2$.*3$d + echo printf("%1$0*2$.*3$d %4$d", 1, 2) +< E1503: Positional argument 3 out of bounds: %1$0*2$.*3$d %4$d *E1504* diff --git a/src/strings.c b/src/strings.c index edf9057f0c..8bcd38a8fa 100644 --- a/src/strings.c +++ b/src/strings.c @@ -2843,6 +2843,12 @@ adjust_types( int *num_posarg, const char *type) { + if (arg <= 0) + { + semsg(_( e_invalid_format_specifier_str), type); + return FAIL; + } + if (*ap_types == NULL || *num_posarg < arg) { int idx; @@ -2876,7 +2882,8 @@ adjust_types( { switch (pt[0]) { - case 'd': case 'i': break; + case 'd': + case 'i': break; default: semsg(_(e_positional_num_field_spec_reused_str_str), arg, format_typename((*ap_types)[arg - 1]), format_typename(type)); return FAIL; diff --git a/src/testdir/test_format.vim b/src/testdir/test_format.vim index b192938d40..b7c8b121a4 100644 --- a/src/testdir/test_format.vim +++ b/src/testdir/test_format.vim @@ -299,6 +299,8 @@ func Test_printf_pos_errors() call v9.CheckLegacyAndVim9Failure(["call printf('%1$1$.5d', 5)"], "E1505:") call v9.CheckLegacyAndVim9Failure(["call printf('%1$5.1$d', 5)"], "E1505:") call v9.CheckLegacyAndVim9Failure(["call printf('%1$1$.1$d', 5)"], "E1505:") + call v9.CheckLegacyAndVim9Failure(["call printf('%1$*1$.*0$s')"], "E1505:") + call v9.CheckLegacyAndVim9Failure(["call printf('%*0$s')"], "E1505:") call v9.CheckLegacyAndVim9Failure(["call printf('%.123456789$d', 5)"], "E1510:") call v9.CheckLegacyAndVim9Failure(["call printf('%.123456789d', 5)"], "E1510:")