mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-04 01:34:25 +00:00 
			
		
		
		
	vim-patch:9.1.0181: no overflow check for string formatting (#27863)
Problem:  no overflow check for string formatting
Solution: Check message formatting function for overflow.
          (Chris van Willegen)
closes: vim/vim#13799
c35fc03dbd
Co-authored-by: Christ van Willegen <cvwillegen@gmail.com>
			
			
This commit is contained in:
		
							
								
								
									
										3
									
								
								runtime/doc/builtin.txt
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										3
									
								
								runtime/doc/builtin.txt
									
									
									
										generated
									
									
									
								
							@@ -5486,6 +5486,9 @@ printf({fmt}, {expr1} ...)                                            *printf()*
 | 
				
			|||||||
		    echo printf("%1$*2$.*3$f", 1.4142135, 6, 2)
 | 
							    echo printf("%1$*2$.*3$f", 1.4142135, 6, 2)
 | 
				
			||||||
<		      1.41
 | 
					<		      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*
 | 
												*E1500*
 | 
				
			||||||
		You cannot mix positional and non-positional arguments: >vim
 | 
							You cannot mix positional and non-positional arguments: >vim
 | 
				
			||||||
		    echo printf("%s%1$s", "One", "Two")
 | 
							    echo printf("%s%1$s", "One", "Two")
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										3
									
								
								runtime/lua/vim/_meta/vimfn.lua
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										3
									
								
								runtime/lua/vim/_meta/vimfn.lua
									
									
									
										generated
									
									
									
								
							@@ -6520,6 +6520,9 @@ function vim.fn.prevnonblank(lnum) end
 | 
				
			|||||||
---     echo printf("%1$*2$.*3$f", 1.4142135, 6, 2)
 | 
					---     echo printf("%1$*2$.*3$f", 1.4142135, 6, 2)
 | 
				
			||||||
--- <      1.41
 | 
					--- <      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*
 | 
					---           *E1500*
 | 
				
			||||||
--- You cannot mix positional and non-positional arguments: >vim
 | 
					--- You cannot mix positional and non-positional arguments: >vim
 | 
				
			||||||
---     echo printf("%s%1$s", "One", "Two")
 | 
					---     echo printf("%s%1$s", "One", "Two")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7836,6 +7836,9 @@ M.funcs = {
 | 
				
			|||||||
          echo printf("%1$*2$.*3$f", 1.4142135, 6, 2)
 | 
					          echo printf("%1$*2$.*3$f", 1.4142135, 6, 2)
 | 
				
			||||||
      <      1.41
 | 
					      <      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*
 | 
					      					*E1500*
 | 
				
			||||||
      You cannot mix positional and non-positional arguments: >vim
 | 
					      You cannot mix positional and non-positional arguments: >vim
 | 
				
			||||||
          echo printf("%s%1$s", "One", "Two")
 | 
					          echo printf("%s%1$s", "One", "Two")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -986,6 +986,40 @@ static int adjust_types(const char ***ap_types, int arg, int *num_posarg, const
 | 
				
			|||||||
  return OK;
 | 
					  return OK;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void format_overflow_error(const char *pstart)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  const char *p = pstart;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  while (ascii_isdigit((int)(*p))) {
 | 
				
			||||||
 | 
					    p++;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  size_t arglen = (size_t)(p - pstart);
 | 
				
			||||||
 | 
					  char *argcopy = xstrnsave(pstart, arglen);
 | 
				
			||||||
 | 
					  semsg(_(e_val_too_large), argcopy);
 | 
				
			||||||
 | 
					  xfree(argcopy);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum { MAX_ALLOWED_STRING_WIDTH = 6400, };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int get_unsigned_int(const char *pstart, const char **p, unsigned *uj)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  *uj = (unsigned)(**p - '0');
 | 
				
			||||||
 | 
					  (*p)++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  while (ascii_isdigit((int)(**p)) && *uj < MAX_ALLOWED_STRING_WIDTH) {
 | 
				
			||||||
 | 
					    *uj = 10 * *uj + (unsigned)(**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, int *num_posarg, const char *fmt, typval_T *tvs)
 | 
					static int parse_fmt_types(const char ***ap_types, int *num_posarg, const char *fmt, typval_T *tvs)
 | 
				
			||||||
  FUNC_ATTR_NONNULL_ARG(1, 2)
 | 
					  FUNC_ATTR_NONNULL_ARG(1, 2)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -1019,6 +1053,7 @@ static int parse_fmt_types(const char ***ap_types, int *num_posarg, const char *
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      // variable for positional arg
 | 
					      // variable for positional arg
 | 
				
			||||||
      int pos_arg = -1;
 | 
					      int pos_arg = -1;
 | 
				
			||||||
 | 
					      const char *pstart = p + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      p++;  // skip '%'
 | 
					      p++;  // skip '%'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1038,11 +1073,12 @@ static int parse_fmt_types(const char ***ap_types, int *num_posarg, const char *
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Positional argument
 | 
					        // Positional argument
 | 
				
			||||||
        unsigned uj = (unsigned)(*p++ - '0');
 | 
					        unsigned uj;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        while (ascii_isdigit((int)(*p))) {
 | 
					        if (get_unsigned_int(pstart, &p, &uj) == FAIL) {
 | 
				
			||||||
          uj = 10 * uj + (unsigned)(*p++ - '0');
 | 
					          goto error;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        pos_arg = (int)uj;
 | 
					        pos_arg = (int)uj;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        any_pos = 1;
 | 
					        any_pos = 1;
 | 
				
			||||||
@@ -1080,10 +1116,10 @@ static int parse_fmt_types(const char ***ap_types, int *num_posarg, const char *
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        if (ascii_isdigit((int)(*p))) {
 | 
					        if (ascii_isdigit((int)(*p))) {
 | 
				
			||||||
          // Positional argument field width
 | 
					          // Positional argument field width
 | 
				
			||||||
          unsigned uj = (unsigned)(*p++ - '0');
 | 
					          unsigned uj;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          while (ascii_isdigit((int)(*p))) {
 | 
					          if (get_unsigned_int(arg + 1, &p, &uj) == FAIL) {
 | 
				
			||||||
            uj = 10 * uj + (unsigned)(*p++ - '0');
 | 
					            goto error;
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          if (*p != '$') {
 | 
					          if (*p != '$') {
 | 
				
			||||||
@@ -1105,10 +1141,11 @@ static int parse_fmt_types(const char ***ap_types, int *num_posarg, const char *
 | 
				
			|||||||
      } else if (ascii_isdigit((int)(*p))) {
 | 
					      } else if (ascii_isdigit((int)(*p))) {
 | 
				
			||||||
        // size_t could be wider than unsigned int; make sure we treat
 | 
					        // size_t could be wider than unsigned int; make sure we treat
 | 
				
			||||||
        // argument like common implementations do
 | 
					        // argument like common implementations do
 | 
				
			||||||
        unsigned uj = (unsigned)(*p++ - '0');
 | 
					        const char *digstart = p;
 | 
				
			||||||
 | 
					        unsigned uj;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        while (ascii_isdigit((int)(*p))) {
 | 
					        if (get_unsigned_int(digstart, &p, &uj) == FAIL) {
 | 
				
			||||||
          uj = 10 * uj + (unsigned)(*p++ - '0');
 | 
					          goto error;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (*p == '$') {
 | 
					        if (*p == '$') {
 | 
				
			||||||
@@ -1126,10 +1163,10 @@ static int parse_fmt_types(const char ***ap_types, int *num_posarg, const char *
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
          if (ascii_isdigit((int)(*p))) {
 | 
					          if (ascii_isdigit((int)(*p))) {
 | 
				
			||||||
            // Parse precision
 | 
					            // Parse precision
 | 
				
			||||||
            unsigned uj = (unsigned)(*p++ - '0');
 | 
					            unsigned uj;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            while (ascii_isdigit((int)(*p))) {
 | 
					            if (get_unsigned_int(arg + 1, &p, &uj) == FAIL) {
 | 
				
			||||||
              uj = 10 * uj + (unsigned)(*p++ - '0');
 | 
					              goto error;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (*p == '$') {
 | 
					            if (*p == '$') {
 | 
				
			||||||
@@ -1152,10 +1189,11 @@ static int parse_fmt_types(const char ***ap_types, int *num_posarg, const char *
 | 
				
			|||||||
        } else if (ascii_isdigit((int)(*p))) {
 | 
					        } else if (ascii_isdigit((int)(*p))) {
 | 
				
			||||||
          // size_t could be wider than unsigned int; make sure we
 | 
					          // size_t could be wider than unsigned int; make sure we
 | 
				
			||||||
          // treat argument like common implementations do
 | 
					          // treat argument like common implementations do
 | 
				
			||||||
          unsigned uj = (unsigned)(*p++ - '0');
 | 
					          const char *digstart = p;
 | 
				
			||||||
 | 
					          unsigned uj;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          while (ascii_isdigit((int)(*p))) {
 | 
					          if (get_unsigned_int(digstart, &p, &uj) == FAIL) {
 | 
				
			||||||
            uj = 10 * uj + (unsigned)(*p++ - '0');
 | 
					            goto error;
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          if (*p == '$') {
 | 
					          if (*p == '$') {
 | 
				
			||||||
@@ -1447,11 +1485,13 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      if (*ptype == '$') {
 | 
					      if (*ptype == '$') {
 | 
				
			||||||
        // Positional argument
 | 
					        // Positional argument
 | 
				
			||||||
        unsigned uj = (unsigned)(*p++ - '0');
 | 
					        const char *digstart = p;
 | 
				
			||||||
 | 
					        unsigned uj;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        while (ascii_isdigit((int)(*p))) {
 | 
					        if (get_unsigned_int(digstart, &p, &uj) == FAIL) {
 | 
				
			||||||
          uj = 10 * uj + (unsigned)(*p++ - '0');
 | 
					          goto error;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        pos_arg = (int)uj;
 | 
					        pos_arg = (int)uj;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        p++;
 | 
					        p++;
 | 
				
			||||||
@@ -1482,15 +1522,18 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      // parse field width
 | 
					      // parse field width
 | 
				
			||||||
      if (*p == '*') {
 | 
					      if (*p == '*') {
 | 
				
			||||||
 | 
					        const char *digstart = p + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        p++;
 | 
					        p++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (ascii_isdigit((int)(*p))) {
 | 
					        if (ascii_isdigit((int)(*p))) {
 | 
				
			||||||
          // Positional argument field width
 | 
					          // Positional argument field width
 | 
				
			||||||
          unsigned uj = (unsigned)(*p++ - '0');
 | 
					          unsigned uj;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          while (ascii_isdigit((int)(*p))) {
 | 
					          if (get_unsigned_int(digstart, &p, &uj) == FAIL) {
 | 
				
			||||||
            uj = 10 * uj + (unsigned)(*p++ - '0');
 | 
					            goto error;
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          arg_idx = (int)uj;
 | 
					          arg_idx = (int)uj;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          p++;
 | 
					          p++;
 | 
				
			||||||
@@ -1502,6 +1545,11 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st
 | 
				
			|||||||
                                      &arg_cur, fmt),
 | 
					                                      &arg_cur, fmt),
 | 
				
			||||||
                          va_arg(ap, int)));
 | 
					                          va_arg(ap, int)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (j > MAX_ALLOWED_STRING_WIDTH) {
 | 
				
			||||||
 | 
					          format_overflow_error(digstart);
 | 
				
			||||||
 | 
					          goto error;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (j >= 0) {
 | 
					        if (j >= 0) {
 | 
				
			||||||
          min_field_width = (size_t)j;
 | 
					          min_field_width = (size_t)j;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
@@ -1511,11 +1559,18 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st
 | 
				
			|||||||
      } else if (ascii_isdigit((int)(*p))) {
 | 
					      } else if (ascii_isdigit((int)(*p))) {
 | 
				
			||||||
        // size_t could be wider than unsigned int; make sure we treat
 | 
					        // size_t could be wider than unsigned int; make sure we treat
 | 
				
			||||||
        // argument like common implementations do
 | 
					        // argument like common implementations do
 | 
				
			||||||
        unsigned uj = (unsigned)(*p++ - '0');
 | 
					        const char *digstart = p;
 | 
				
			||||||
 | 
					        unsigned uj;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        while (ascii_isdigit((int)(*p))) {
 | 
					        if (get_unsigned_int(digstart, &p, &uj) == FAIL) {
 | 
				
			||||||
          uj = 10 * uj + (unsigned)(*p++ - '0');
 | 
					          goto error;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (uj > MAX_ALLOWED_STRING_WIDTH) {
 | 
				
			||||||
 | 
					          format_overflow_error(digstart);
 | 
				
			||||||
 | 
					          goto error;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        min_field_width = uj;
 | 
					        min_field_width = uj;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1527,22 +1582,32 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st
 | 
				
			|||||||
        if (ascii_isdigit((int)(*p))) {
 | 
					        if (ascii_isdigit((int)(*p))) {
 | 
				
			||||||
          // size_t could be wider than unsigned int; make sure we
 | 
					          // size_t could be wider than unsigned int; make sure we
 | 
				
			||||||
          // treat argument like common implementations do
 | 
					          // treat argument like common implementations do
 | 
				
			||||||
          unsigned uj = (unsigned)(*p++ - '0');
 | 
					          const char *digstart = p;
 | 
				
			||||||
 | 
					          unsigned uj;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          while (ascii_isdigit((int)(*p))) {
 | 
					          if (get_unsigned_int(digstart, &p, &uj) == FAIL) {
 | 
				
			||||||
            uj = 10 * uj + (unsigned)(*p++ - '0');
 | 
					            goto error;
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          if (uj > MAX_ALLOWED_STRING_WIDTH) {
 | 
				
			||||||
 | 
					            format_overflow_error(digstart);
 | 
				
			||||||
 | 
					            goto error;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          precision = uj;
 | 
					          precision = uj;
 | 
				
			||||||
        } else if (*p == '*') {
 | 
					        } else if (*p == '*') {
 | 
				
			||||||
 | 
					          const char *digstart = p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          p++;
 | 
					          p++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          if (ascii_isdigit((int)(*p))) {
 | 
					          if (ascii_isdigit((int)(*p))) {
 | 
				
			||||||
            // positional argument
 | 
					            // positional argument
 | 
				
			||||||
            unsigned uj = (unsigned)(*p++ - '0');
 | 
					            unsigned uj;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            while (ascii_isdigit((int)(*p))) {
 | 
					            if (get_unsigned_int(digstart, &p, &uj) == FAIL) {
 | 
				
			||||||
              uj = 10 * uj + (unsigned)(*p++ - '0');
 | 
					              goto error;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            arg_idx = (int)uj;
 | 
					            arg_idx = (int)uj;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            p++;
 | 
					            p++;
 | 
				
			||||||
@@ -1554,6 +1619,11 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st
 | 
				
			|||||||
                                        &arg_cur, fmt),
 | 
					                                        &arg_cur, fmt),
 | 
				
			||||||
                            va_arg(ap, int)));
 | 
					                            va_arg(ap, int)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          if (j > MAX_ALLOWED_STRING_WIDTH) {
 | 
				
			||||||
 | 
					            format_overflow_error(digstart);
 | 
				
			||||||
 | 
					            goto error;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          if (j >= 0) {
 | 
					          if (j >= 0) {
 | 
				
			||||||
            precision = (size_t)j;
 | 
					            precision = (size_t)j;
 | 
				
			||||||
          } else {
 | 
					          } else {
 | 
				
			||||||
@@ -2160,6 +2230,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st
 | 
				
			|||||||
    emsg(_("E767: Too many arguments to printf()"));
 | 
					    emsg(_("E767: Too many arguments to printf()"));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					error:
 | 
				
			||||||
  xfree(ap_types);
 | 
					  xfree(ap_types);
 | 
				
			||||||
  va_end(ap);
 | 
					  va_end(ap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -105,67 +105,6 @@ func Test_printf_pos_misc()
 | 
				
			|||||||
  END
 | 
					  END
 | 
				
			||||||
  call CheckLegacyAndVim9Success(lines)
 | 
					  call CheckLegacyAndVim9Success(lines)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$d%2$d', 1, 3, 4)"], "E767:")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%2$d%d', 1, 3)"], "E1500:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%d%2$d', 1, 3)"], "E1500:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%2$*1$d%d', 1, 3)"], "E1500:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%d%2$*1$d', 1, 3)"], "E1500:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%2$.*1$d%d', 1, 3)"], "E1500:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%d%2$.*1$d', 1, 3)"], "E1500:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$%')"], "E1500:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$')"], "E1500:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$_')"], "E1500:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$*3$.*d', 3)"], "E1500:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$*.*2$d', 3)"], "E1500:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$*.*d', 3)"], "E1500:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%*.*1$d', 3)"], "E1500:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%*1$.*d', 3)"], "E1500:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%*1$.*1$d', 3)"], "E1500:")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%2$d', 3, 3)"], "E1501:")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%2$*1$d %1$ld', 3, 3)"], "E1502:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$s %1$*1$d', 3)"], "E1502:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$p %1$*1$d', 3)"], "E1502:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$f %1$*1$d', 3)"], "E1502:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$lud %1$*1$d', 3)"], "E1502:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$llud %1$*1$d', 3)"], "E1502:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$lld %1$*1$d', 3)"], "E1502:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$s %1$*1$d', 3)"], "E1502:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$c %1$*1$d', 3)"], "E1502:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$ld %1$*1$d', 3)"], "E1502:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$ld %2$*1$d', 3, 3)"], "E1502:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$*1$ld', 3)"], "E1502:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$*1$.*1$ld', 3)"], "E1502:")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$d%2$d', 3)"], "E1503:")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$d %1$s', 3)"], "E1504:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$ld %1$s', 3)"], "E1504:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$ud %1$d', 3)"], "E1504:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$s %1$f', 3.0)"], "E1504:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$*1$d %1$ld', 3)"], "E1504:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$s %1$d', 3)"], "E1504:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$p %1$d', 3)"], "E1504:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$f %1$d', 3)"], "E1504:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$lud %1$d', 3)"], "E1504:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$llud %1$d', 3)"], "E1504:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$lld %1$d', 3)"], "E1504:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$s %1$d', 3)"], "E1504:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$c %1$d', 3)"], "E1504:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$ld %1$d', 3)"], "E1504:")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$.2$d', 3)"], "E1505:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%01$d', 3)"], "E1505:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%01$0d', 3)"], "E1505:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$*2d', 3)"], "E1505:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$*3.*2$d', 3)"], "E1505:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$*3$.2$d', 3)"], "E1505:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$*3$.*2d', 3)"], "E1505:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$1$.5d', 5)"], "E1505:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$5.1$d', 5)"], "E1505:")
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(["call printf('%1$1$.1$d', 5)"], "E1505:")
 | 
					 | 
				
			||||||
endfunc
 | 
					endfunc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func Test_printf_pos_float()
 | 
					func Test_printf_pos_float()
 | 
				
			||||||
@@ -287,8 +226,6 @@ func Test_printf_pos_float()
 | 
				
			|||||||
      call assert_equal("str2float('nan')", printf('%1$S', -0.0 / 0.0))
 | 
					      call assert_equal("str2float('nan')", printf('%1$S', -0.0 / 0.0))
 | 
				
			||||||
  END
 | 
					  END
 | 
				
			||||||
  call CheckLegacyAndVim9Success(lines)
 | 
					  call CheckLegacyAndVim9Success(lines)
 | 
				
			||||||
 | 
					 | 
				
			||||||
  call CheckLegacyAndVim9Failure(['echo printf("%f", "a")'], 'E807:')
 | 
					 | 
				
			||||||
endfunc
 | 
					endfunc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func Test_printf_pos_errors()
 | 
					func Test_printf_pos_errors()
 | 
				
			||||||
@@ -299,6 +236,111 @@ func Test_printf_pos_errors()
 | 
				
			|||||||
  call CheckLegacyAndVim9Failure(['echo printf("%1$s")'], 'E1503:')
 | 
					  call CheckLegacyAndVim9Failure(['echo printf("%1$s")'], 'E1503:')
 | 
				
			||||||
  call CheckLegacyAndVim9Failure(['echo printf("%1$d", 1.2)'], 'E805:')
 | 
					  call CheckLegacyAndVim9Failure(['echo printf("%1$d", 1.2)'], 'E805:')
 | 
				
			||||||
  call CheckLegacyAndVim9Failure(['echo printf("%1$f")'], 'E1503:')
 | 
					  call CheckLegacyAndVim9Failure(['echo printf("%1$f")'], 'E1503:')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(['echo printf("%f", "a")'], 'E807:')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$d%2$d', 1, 3, 4)"], "E767:")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%2$d%d', 1, 3)"], "E1500:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%d%2$d', 1, 3)"], "E1500:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%2$*1$d%d', 1, 3)"], "E1500:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%d%2$*1$d', 1, 3)"], "E1500:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%2$.*1$d%d', 1, 3)"], "E1500:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%d%2$.*1$d', 1, 3)"], "E1500:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$%')"], "E1500:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$')"], "E1500:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$_')"], "E1500:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$*3$.*d', 3)"], "E1500:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$*.*2$d', 3)"], "E1500:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$*.*d', 3)"], "E1500:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%*.*1$d', 3)"], "E1500:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%*1$.*d', 3)"], "E1500:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%*1$.*1$d', 3)"], "E1500:")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%2$d', 3, 3)"], "E1501:")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%2$*1$d %1$ld', 3, 3)"], "E1502:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$s %1$*1$d', 3)"], "E1502:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$p %1$*1$d', 3)"], "E1502:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$f %1$*1$d', 3)"], "E1502:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$lud %1$*1$d', 3)"], "E1502:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$llud %1$*1$d', 3)"], "E1502:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$lld %1$*1$d', 3)"], "E1502:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$s %1$*1$d', 3)"], "E1502:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$c %1$*1$d', 3)"], "E1502:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$ld %1$*1$d', 3)"], "E1502:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$ld %2$*1$d', 3, 3)"], "E1502:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$*1$ld', 3)"], "E1502:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$*1$.*1$ld', 3)"], "E1502:")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$d%2$d', 3)"], "E1503:")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$d %1$s', 3)"], "E1504:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$ld %1$s', 3)"], "E1504:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$ud %1$d', 3)"], "E1504:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$s %1$f', 3.0)"], "E1504:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$*1$d %1$ld', 3)"], "E1504:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$s %1$d', 3)"], "E1504:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$p %1$d', 3)"], "E1504:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$f %1$d', 3)"], "E1504:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$lud %1$d', 3)"], "E1504:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$llud %1$d', 3)"], "E1504:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$lld %1$d', 3)"], "E1504:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$s %1$d', 3)"], "E1504:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$c %1$d', 3)"], "E1504:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$ld %1$d', 3)"], "E1504:")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$.2$d', 3)"], "E1505:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%01$d', 3)"], "E1505:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%01$0d', 3)"], "E1505:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$*2d', 3)"], "E1505:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$*3.*2$d', 3)"], "E1505:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$*3$.2$d', 3)"], "E1505:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$*3$.*2d', 3)"], "E1505:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$1$.5d', 5)"], "E1505:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$5.1$d', 5)"], "E1505:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$1$.1$d', 5)"], "E1505:")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%.123456789$d', 5)"], "E1510:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%.123456789d', 5)"], "E1510:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%123456789$d', 5)"], "E1510:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%123456789d', 5)"], "E1510:")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%123456789$5.5d', 5)"], "E1510:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$123456789.5d', 5)"], "E1510:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$5.123456789d', 5)"], "E1510:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%123456789$987654321.5d', 5)"], "E1510:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$123456789.987654321d', 5)"], "E1510:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%123456789$5.987654321d', 5)"], "E1510:")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%123456789$*1$.5d', 5)"], "E1510:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$*123456789$.5d', 5)"], "E1510:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$*1$.123456789d', 5)"], "E1510:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%123456789$*987654321$.5d', 5)"], "E1510:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$*123456789$.987654321d', 5)"], "E1510:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%123456789$*1$.987654321d', 5)"], "E1510:")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%123456789$5.*1$d', 5)"], "E1510:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$123456789.*1$d', 5)"], "E1510:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$5.*123456789$d', 5)"], "E1510:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%123456789$987654321.*1$d', 5)"], "E1510:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$123456789.*987654321$d', 5)"], "E1510:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%123456789$5.*987654321$d', 5)"], "E1510:")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%123456789$*1$.*1$d', 5)"], "E1510:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$*123456789$.*1$d', 5)"], "E1510:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$*1$.*123456789d', 5)"], "E1510:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%123456789$*987654321$.*1$d', 5)"], "E1510:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$*123456789$.*987654321$d', 5)"], "E1510:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%123456789$*1$.*987654321$d', 5)"], "E1510:")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$*2$.*1$d', 5, 9999)"], "E1510:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$*1$.*2$d', 5, 9999)"], "E1510:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%2$*3$.*1$d', 5, 9123, 9321)"], "E1510:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$*2$.*3$d', 5, 9123, 9321)"], "E1510:")
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%2$*1$.*3$d', 5, 9123, 9312)"], "E1510:")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call CheckLegacyAndVim9Failure(["call printf('%1$*2$d', 5, 9999)"], "E1510:")
 | 
				
			||||||
endfunc
 | 
					endfunc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func Test_printf_pos_64bit()
 | 
					func Test_printf_pos_64bit()
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user