]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.1.0181: no overflow check for string formatting v9.1.0181
authorChrist van Willegen <cvwillegen@gmail.com>
Thu, 14 Mar 2024 17:30:41 +0000 (18:30 +0100)
committerChristian Brabandt <cb@256bit.org>
Thu, 14 Mar 2024 17:58:04 +0000 (18:58 +0100)
Problem:  no overflow check for string formatting
Solution: Check message formatting function for overflow.
          (Chris van Willegen)

closes: #13799

Signed-off-by: Christ van Willegen <cvwillegen@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
runtime/doc/builtin.txt
src/strings.c
src/testdir/test_format.vim
src/version.c

index ab63b0ef091de0f213fcdeac4a3a2eb74fef06c6..c857fbc3dedb29f3660568ee137c44855ffbf937 100644 (file)
@@ -1,4 +1,4 @@
-*builtin.txt*  For Vim version 9.1.  Last change: 2024 Mar 13
+*builtin.txt*  For Vim version 9.1.  Last change: 2024 Mar 14
 
 
                  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -7105,6 +7105,9 @@ printf({fmt}, {expr1} ...)                                *printf()*
                    echo printf("%1$*2$.*3$f", 1.4142135, 6, 2)
 <                    1.41
 
+               You will get an overflow error |E1510|, when the field-width
+               or precision will result in a string longer than 6400 chars.
+
                                                        *E1500*
                You cannot mix positional and non-positional arguments: >
                    echo printf("%s%1$s", "One", "Two")
index b38c3d0bd7ef89bd1a82a57bf2cde89a200198b7..33de175f298bd4e30822c4f23c1b2f911489a080 100644 (file)
@@ -2468,6 +2468,55 @@ adjust_types(
     return OK;
 }
 
+    static void
+format_overflow_error(const char *pstart)
+{
+    size_t     arglen = 0;
+    char       *argcopy = NULL;
+    const char *p = pstart;
+
+    while (VIM_ISDIGIT((int)(*p)))
+       ++p;
+
+    arglen = p - pstart;
+    argcopy = ALLOC_CLEAR_MULT(char, arglen + 1);
+    if (argcopy != NULL)
+    {
+       strncpy(argcopy, pstart, arglen);
+       semsg(_( e_val_too_large), argcopy);
+       free(argcopy);
+    }
+    else
+       semsg(_(e_out_of_memory_allocating_nr_bytes), arglen);
+}
+
+#define MAX_ALLOWED_STRING_WIDTH 6400
+
+    static int
+get_unsigned_int(
+    const char *pstart,
+    const char **p,
+    unsigned int *uj)
+{
+    *uj = **p - '0';
+    ++*p;
+
+    while (VIM_ISDIGIT((int)(**p)) && *uj < MAX_ALLOWED_STRING_WIDTH)
+    {
+       *uj = 10 * *uj + (unsigned int)(**p - '0');
+       ++*p;
+    }
+
+    if (*uj > MAX_ALLOWED_STRING_WIDTH)
+    {
+       format_overflow_error(pstart);
+       return FAIL;
+    }
+
+    return OK;
+}
+
+
     static int
 parse_fmt_types(
     const char  ***ap_types,
@@ -2511,6 +2560,7 @@ parse_fmt_types(
            // variable for positional arg
            int         pos_arg = -1;
            const char  *ptype = NULL;
+           const char  *pstart = p+1;
 
            p++;  // skip '%'
 
@@ -2531,10 +2581,11 @@ parse_fmt_types(
                }
 
                // Positional argument
-               unsigned int uj = *p++ - '0';
+               unsigned int uj;
+
+               if (get_unsigned_int(pstart, &p, &uj) == FAIL)
+                   goto error;
 
-               while (VIM_ISDIGIT((int)(*p)))
-                   uj = 10 * uj + (unsigned int)(*p++ - '0');
                pos_arg = uj;
 
                any_pos = 1;
@@ -2571,10 +2622,10 @@ parse_fmt_types(
                if (VIM_ISDIGIT((int)(*p)))
                {
                    // Positional argument field width
-                   unsigned int uj = *p++ - '0';
+                   unsigned int uj;
 
-                   while (VIM_ISDIGIT((int)(*p)))
-                       uj = 10 * uj + (unsigned int)(*p++ - '0');
+                   if (get_unsigned_int(arg + 1, &p, &uj) == FAIL)
+                       goto error;
 
                    if (*p != '$')
                    {
@@ -2601,10 +2652,11 @@ parse_fmt_types(
            {
                // size_t could be wider than unsigned int; make sure we treat
                // argument like common implementations do
-               unsigned int uj = *p++ - '0';
+               const char *digstart = p;
+               unsigned int uj;
 
-               while (VIM_ISDIGIT((int)(*p)))
-                   uj = 10 * uj + (unsigned int)(*p++ - '0');
+               if (get_unsigned_int(digstart, &p, &uj) == FAIL)
+                   goto error;
 
                if (*p == '$')
                {
@@ -2625,10 +2677,10 @@ parse_fmt_types(
                    if (VIM_ISDIGIT((int)(*p)))
                    {
                        // Parse precision
-                       unsigned int uj = *p++ - '0';
+                       unsigned int uj;
 
-                       while (VIM_ISDIGIT((int)(*p)))
-                           uj = 10 * uj + (unsigned int)(*p++ - '0');
+                       if (get_unsigned_int(arg + 1, &p, &uj) == FAIL)
+                           goto error;
 
                        if (*p == '$')
                        {
@@ -2656,10 +2708,11 @@ parse_fmt_types(
                {
                    // size_t could be wider than unsigned int; make sure we
                    // treat argument like common implementations do
-                   unsigned int uj = *p++ - '0';
+                   const char *digstart = p;
+                   unsigned int uj;
 
-                   while (VIM_ISDIGIT((int)(*p)))
-                       uj = 10 * uj + (unsigned int)(*p++ - '0');
+                   if (get_unsigned_int(digstart, &p, &uj) == FAIL)
+                       goto error;
 
                    if (*p == '$')
                    {
@@ -2968,10 +3021,12 @@ vim_vsnprintf_typval(
            if (*ptype == '$')
            {
                // Positional argument
-               unsigned int uj = *p++ - '0';
+               const char *digstart = p;
+               unsigned int uj;
+
+               if (get_unsigned_int(digstart, &p, &uj) == FAIL)
+                   goto error;
 
-               while (VIM_ISDIGIT((int)(*p)))
-                   uj = 10 * uj + (unsigned int)(*p++ - '0');
                pos_arg = uj;
 
                ++p;
@@ -3002,16 +3057,18 @@ vim_vsnprintf_typval(
            if (*p == '*')
            {
                int j;
+               const char *digstart = p + 1;
 
                p++;
 
                if (VIM_ISDIGIT((int)(*p)))
                {
                    // Positional argument field width
-                   unsigned int uj = *p++ - '0';
+                   unsigned int uj;
+
+                   if (get_unsigned_int(digstart, &p, &uj) == FAIL)
+                       goto error;
 
-                   while (VIM_ISDIGIT((int)(*p)))
-                       uj = 10 * uj + (unsigned int)(*p++ - '0');
                    arg_idx = uj;
 
                    ++p;
@@ -3025,6 +3082,12 @@ vim_vsnprintf_typval(
                                     &arg_cur, fmt),
                        va_arg(ap, int));
 
+               if (j > MAX_ALLOWED_STRING_WIDTH)
+               {
+                   format_overflow_error(digstart);
+                   goto error;
+               }
+
                if (j >= 0)
                    min_field_width = j;
                else
@@ -3037,10 +3100,18 @@ vim_vsnprintf_typval(
            {
                // size_t could be wider than unsigned int; make sure we treat
                // argument like common implementations do
-               unsigned int uj = *p++ - '0';
+               const char *digstart = p;
+               unsigned int uj;
+
+               if (get_unsigned_int(digstart, &p, &uj) == FAIL)
+                   goto error;
+
+               if (uj > MAX_ALLOWED_STRING_WIDTH)
+               {
+                   format_overflow_error(digstart);
+                   goto error;
+               }
 
-               while (VIM_ISDIGIT((int)(*p)))
-                   uj = 10 * uj + (unsigned int)(*p++ - '0');
                min_field_width = uj;
            }
 
@@ -3054,25 +3125,35 @@ vim_vsnprintf_typval(
                {
                    // size_t could be wider than unsigned int; make sure we
                    // treat argument like common implementations do
-                   unsigned int uj = *p++ - '0';
+                   const char *digstart = p;
+                   unsigned int uj;
+
+                   if (get_unsigned_int(digstart, &p, &uj) == FAIL)
+                       goto error;
+
+                   if (uj > MAX_ALLOWED_STRING_WIDTH)
+                   {
+                       format_overflow_error(digstart);
+                       goto error;
+                   }
 
-                   while (VIM_ISDIGIT((int)(*p)))
-                       uj = 10 * uj + (unsigned int)(*p++ - '0');
                    precision = uj;
                }
                else if (*p == '*')
                {
                    int j;
+                   const char *digstart = p;
 
                    p++;
 
                    if (VIM_ISDIGIT((int)(*p)))
                    {
                        // positional argument
-                       unsigned int uj = *p++ - '0';
+                       unsigned int uj;
+
+                       if (get_unsigned_int(digstart, &p, &uj) == FAIL)
+                           goto error;
 
-                       while (VIM_ISDIGIT((int)(*p)))
-                           uj = 10 * uj + (unsigned int)(*p++ - '0');
                        arg_idx = uj;
 
                        ++p;
@@ -3086,6 +3167,12 @@ vim_vsnprintf_typval(
                                         &arg_cur, fmt),
                            va_arg(ap, int));
 
+                   if (j > MAX_ALLOWED_STRING_WIDTH)
+                   {
+                       format_overflow_error(digstart);
+                       goto error;
+                   }
+
                    if (j >= 0)
                        precision = j;
                    else
@@ -3873,6 +3960,7 @@ vim_vsnprintf_typval(
     if (tvs != NULL && tvs[num_posarg != 0 ? num_posarg : arg_idx - 1].v_type != VAR_UNKNOWN)
        emsg(_(e_too_many_arguments_to_printf));
 
+error:
     vim_free((char*)ap_types);
     va_end(ap);
 
index af364c2a158bc7bfa7faf3f10c2279affd7ffcea..785348bee84d0760d80332b94e518e5cb63c7318 100644 (file)
@@ -105,67 +105,6 @@ func Test_printf_pos_misc()
   END
   call v9.CheckLegacyAndVim9Success(lines)
 
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$d%2$d', 1, 3, 4)"], "E767:")
-
-  call v9.CheckLegacyAndVim9Failure(["call printf('%2$d%d', 1, 3)"], "E1500:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%d%2$d', 1, 3)"], "E1500:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%2$*1$d%d', 1, 3)"], "E1500:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%d%2$*1$d', 1, 3)"], "E1500:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%2$.*1$d%d', 1, 3)"], "E1500:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%d%2$.*1$d', 1, 3)"], "E1500:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$%')"], "E1500:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$')"], "E1500:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$_')"], "E1500:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$*3$.*d', 3)"], "E1500:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$*.*2$d', 3)"], "E1500:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$*.*d', 3)"], "E1500:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%*.*1$d', 3)"], "E1500:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%*1$.*d', 3)"], "E1500:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%*1$.*1$d', 3)"], "E1500:")
-
-  call v9.CheckLegacyAndVim9Failure(["call printf('%2$d', 3, 3)"], "E1501:")
-
-  call v9.CheckLegacyAndVim9Failure(["call printf('%2$*1$d %1$ld', 3, 3)"], "E1502:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$s %1$*1$d', 3)"], "E1502:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$p %1$*1$d', 3)"], "E1502:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$f %1$*1$d', 3)"], "E1502:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$lud %1$*1$d', 3)"], "E1502:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$llud %1$*1$d', 3)"], "E1502:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$lld %1$*1$d', 3)"], "E1502:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$s %1$*1$d', 3)"], "E1502:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$c %1$*1$d', 3)"], "E1502:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$ld %1$*1$d', 3)"], "E1502:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$ld %2$*1$d', 3, 3)"], "E1502:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$*1$ld', 3)"], "E1502:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$*1$.*1$ld', 3)"], "E1502:")
-
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$d%2$d', 3)"], "E1503:")
-
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$d %1$s', 3)"], "E1504:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$ld %1$s', 3)"], "E1504:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$ud %1$d', 3)"], "E1504:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$s %1$f', 3.0)"], "E1504:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$*1$d %1$ld', 3)"], "E1504:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$s %1$d', 3)"], "E1504:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$p %1$d', 3)"], "E1504:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$f %1$d', 3)"], "E1504:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$lud %1$d', 3)"], "E1504:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$llud %1$d', 3)"], "E1504:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$lld %1$d', 3)"], "E1504:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$s %1$d', 3)"], "E1504:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$c %1$d', 3)"], "E1504:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$ld %1$d', 3)"], "E1504:")
-
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$.2$d', 3)"], "E1505:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%01$d', 3)"], "E1505:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%01$0d', 3)"], "E1505:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$*2d', 3)"], "E1505:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$*3.*2$d', 3)"], "E1505:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$*3$.2$d', 3)"], "E1505:")
-  call v9.CheckLegacyAndVim9Failure(["call printf('%1$*3$.*2d', 3)"], "E1505:")
-  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:")
 endfunc
 
 func Test_printf_pos_float()
@@ -287,8 +226,6 @@ func Test_printf_pos_float()
       call assert_equal('nan', printf('%1$S', -0.0 / 0.0))
   END
   call v9.CheckLegacyAndVim9Success(lines)
-
-  call v9.CheckLegacyAndVim9Failure(['echo printf("%f", "a")'], 'E807:')
 endfunc
 
 func Test_printf_pos_errors()
@@ -299,6 +236,111 @@ func Test_printf_pos_errors()
   call v9.CheckLegacyAndVim9Failure(['echo printf("%1$s")'], 'E1503:')
   call v9.CheckLegacyAndVim9Failure(['echo printf("%1$d", 1.2)'], 'E805:')
   call v9.CheckLegacyAndVim9Failure(['echo printf("%1$f")'], 'E1503:')
+
+  call v9.CheckLegacyAndVim9Failure(['echo printf("%f", "a")'], 'E807:')
+
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$d%2$d', 1, 3, 4)"], "E767:")
+
+  call v9.CheckLegacyAndVim9Failure(["call printf('%2$d%d', 1, 3)"], "E1500:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%d%2$d', 1, 3)"], "E1500:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%2$*1$d%d', 1, 3)"], "E1500:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%d%2$*1$d', 1, 3)"], "E1500:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%2$.*1$d%d', 1, 3)"], "E1500:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%d%2$.*1$d', 1, 3)"], "E1500:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$%')"], "E1500:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$')"], "E1500:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$_')"], "E1500:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$*3$.*d', 3)"], "E1500:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$*.*2$d', 3)"], "E1500:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$*.*d', 3)"], "E1500:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%*.*1$d', 3)"], "E1500:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%*1$.*d', 3)"], "E1500:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%*1$.*1$d', 3)"], "E1500:")
+
+  call v9.CheckLegacyAndVim9Failure(["call printf('%2$d', 3, 3)"], "E1501:")
+
+  call v9.CheckLegacyAndVim9Failure(["call printf('%2$*1$d %1$ld', 3, 3)"], "E1502:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$s %1$*1$d', 3)"], "E1502:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$p %1$*1$d', 3)"], "E1502:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$f %1$*1$d', 3)"], "E1502:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$lud %1$*1$d', 3)"], "E1502:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$llud %1$*1$d', 3)"], "E1502:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$lld %1$*1$d', 3)"], "E1502:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$s %1$*1$d', 3)"], "E1502:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$c %1$*1$d', 3)"], "E1502:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$ld %1$*1$d', 3)"], "E1502:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$ld %2$*1$d', 3, 3)"], "E1502:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$*1$ld', 3)"], "E1502:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$*1$.*1$ld', 3)"], "E1502:")
+
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$d%2$d', 3)"], "E1503:")
+
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$d %1$s', 3)"], "E1504:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$ld %1$s', 3)"], "E1504:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$ud %1$d', 3)"], "E1504:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$s %1$f', 3.0)"], "E1504:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$*1$d %1$ld', 3)"], "E1504:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$s %1$d', 3)"], "E1504:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$p %1$d', 3)"], "E1504:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$f %1$d', 3)"], "E1504:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$lud %1$d', 3)"], "E1504:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$llud %1$d', 3)"], "E1504:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$lld %1$d', 3)"], "E1504:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$s %1$d', 3)"], "E1504:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$c %1$d', 3)"], "E1504:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$ld %1$d', 3)"], "E1504:")
+
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$.2$d', 3)"], "E1505:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%01$d', 3)"], "E1505:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%01$0d', 3)"], "E1505:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$*2d', 3)"], "E1505:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$*3.*2$d', 3)"], "E1505:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$*3$.2$d', 3)"], "E1505:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$*3$.*2d', 3)"], "E1505:")
+  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('%.123456789$d', 5)"], "E1510:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%.123456789d', 5)"], "E1510:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%123456789$d', 5)"], "E1510:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%123456789d', 5)"], "E1510:")
+
+  call v9.CheckLegacyAndVim9Failure(["call printf('%123456789$5.5d', 5)"], "E1510:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$123456789.5d', 5)"], "E1510:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$5.123456789d', 5)"], "E1510:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%123456789$987654321.5d', 5)"], "E1510:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$123456789.987654321d', 5)"], "E1510:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%123456789$5.987654321d', 5)"], "E1510:")
+
+  call v9.CheckLegacyAndVim9Failure(["call printf('%123456789$*1$.5d', 5)"], "E1510:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$*123456789$.5d', 5)"], "E1510:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$*1$.123456789d', 5)"], "E1510:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%123456789$*987654321$.5d', 5)"], "E1510:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$*123456789$.987654321d', 5)"], "E1510:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%123456789$*1$.987654321d', 5)"], "E1510:")
+
+  call v9.CheckLegacyAndVim9Failure(["call printf('%123456789$5.*1$d', 5)"], "E1510:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$123456789.*1$d', 5)"], "E1510:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$5.*123456789$d', 5)"], "E1510:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%123456789$987654321.*1$d', 5)"], "E1510:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$123456789.*987654321$d', 5)"], "E1510:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%123456789$5.*987654321$d', 5)"], "E1510:")
+
+  call v9.CheckLegacyAndVim9Failure(["call printf('%123456789$*1$.*1$d', 5)"], "E1510:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$*123456789$.*1$d', 5)"], "E1510:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$*1$.*123456789d', 5)"], "E1510:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%123456789$*987654321$.*1$d', 5)"], "E1510:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$*123456789$.*987654321$d', 5)"], "E1510:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%123456789$*1$.*987654321$d', 5)"], "E1510:")
+
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$*2$.*1$d', 5, 9999)"], "E1510:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$*1$.*2$d', 5, 9999)"], "E1510:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%2$*3$.*1$d', 5, 9123, 9321)"], "E1510:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$*2$.*3$d', 5, 9123, 9321)"], "E1510:")
+  call v9.CheckLegacyAndVim9Failure(["call printf('%2$*1$.*3$d', 5, 9123, 9312)"], "E1510:")
+
+  call v9.CheckLegacyAndVim9Failure(["call printf('%1$*2$d', 5, 9999)"], "E1510:")
 endfunc
 
 func Test_printf_pos_64bit()
index 77c958662f39315f11c8e058b575146155fee5c6..36c1205777d7799d6f813fb95fe7e88341a0957d 100644 (file)
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    181,
 /**/
     180,
 /**/