Patch 8.2.0066
Problem:    Some corners of vim_snprintf() are not tested.
Solution:   Add a test in C. (Dominique Pelle, closes #5422)
Files:      src/message_test.c


*** ../vim-8.2.0065/src/message_test.c  2019-12-30 17:55:30.460513283 +0100
--- src/message_test.c  2019-12-31 19:24:11.385712386 +0100
***************
*** 22,27 ****
--- 22,45 ----
  // static.
  #include "message.c"
  
+ #ifndef MIN
+ # define MIN(x,y) ((x) < (y) ? (x) : (y))
+ #endif
+ 
+ // These formats are not standard in C printf() function.
+ // Use a global variable rather than a literal format to disable
+ // -Wformat compiler warnings:
+ //
+ // - warning: '0' flag used with ‘%p’ gnu_printf format
+ // - warning: format ‘%S’ expects argument of type ‘wchar_t *’, but argument 
4 has type ‘char *’
+ // - warning: unknown conversion type character ‘b’ in format
+ //
+ // These formats are in practise only used from vim script printf()
+ // function and never as literals in C code.
+ char *fmt_012p = "%012p";
+ char *fmt_5S   = "%5S";
+ char *fmt_06b  = "%06b";
+ 
  /*
   * Test trunc_string().
   */
***************
*** 93,98 ****
--- 111,259 ----
      vim_free(s);
  }
  
+ /*
+  * Test vim_snprintf() with a focus on checking that truncation is
+  * correct when buffer is small, since it cannot be tested from
+  * vim scrip tests. Check that:
+  * - no buffer overflows happens (with valgrind or asan)
+  * - output string is always NUL terminated.
+  *
+  * Not all formats of vim_snprintf() are checked here. They are
+  * checked more exhaustively in Test_printf*() vim script tests.
+  */
+     static void
+ test_vim_snprintf(void)
+ {
+     int               n;
+     size_t    bsize;
+     int               bsize_int;
+     char      *ptr = (char *)0x87654321;
+ 
+     // Loop on various buffer sizes to make sure that truncation of
+     // vim_snprintf() is correct.
+     for (bsize = 0; bsize < 15; ++bsize)
+     {
+       bsize_int = (int)bsize - 1;
+ 
+       // buf is the heap rather than in the stack
+       // so valgrind can detect buffer overflows if any.
+       // Use malloc() rather than alloc() as test checks with 0-size
+       // buffer and its content should then never be used.
+       char *buf = malloc(bsize);
+ 
+       n = vim_snprintf(buf, bsize, "%d", 1234567);
+       assert(n == 7);
+       assert(bsize == 0 || STRNCMP(buf, "1234567", bsize_int) == 0);
+       assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
+ 
+       n = vim_snprintf(buf, bsize, "%ld", 1234567L);
+       assert(n == 7);
+       assert(bsize == 0 || STRNCMP(buf, "1234567", bsize_int) == 0);
+       assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
+ 
+       n = vim_snprintf(buf, bsize, "%9ld", 1234567L);
+       assert(n == 9);
+       assert(bsize == 0 || STRNCMP(buf, "  1234567", bsize_int) == 0);
+       assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
+ 
+       n = vim_snprintf(buf, bsize, "%-9ld", 1234567L);
+       assert(n == 9);
+       assert(bsize == 0 || STRNCMP(buf, "1234567  ", bsize_int) == 0);
+       assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
+ 
+       n = vim_snprintf(buf, bsize, "%x", 0xdeadbeef);
+       assert(n == 8);
+       assert(bsize == 0 || STRNCMP(buf, "deadbeef", bsize_int) == 0);
+       assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
+ 
+       n = vim_snprintf(buf, bsize, fmt_06b, 12);
+       assert(n == 6);
+       assert(bsize == 0 || STRNCMP(buf, "001100", bsize_int) == 0);
+       assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
+ 
+ #ifdef FEAT_FLOAT
+       n = vim_snprintf(buf, bsize, "%f", 1.234);
+       assert(n == 8);
+       assert(bsize == 0 || STRNCMP(buf, "1.234000", bsize_int) == 0);
+       assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
+ 
+       n = vim_snprintf(buf, bsize, "%e", 1.234);
+       assert(n == 12);
+       assert(bsize == 0 || STRNCMP(buf, "1.234000e+00", bsize_int) == 0);
+       assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
+ 
+       n = vim_snprintf(buf, bsize, "%f", 0.0/0.0);
+       assert(n == 3);
+       assert(bsize == 0 || STRNCMP(buf, "nan", bsize_int) == 0);
+       assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
+ 
+       n = vim_snprintf(buf, bsize, "%f", 1.0/0.0);
+       assert(n == 3);
+       assert(bsize == 0 || STRNCMP(buf, "inf", bsize_int) == 0);
+       assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
+ 
+       n = vim_snprintf(buf, bsize, "%f", -1.0/0.0);
+       assert(n == 4);
+       assert(bsize == 0 || STRNCMP(buf, "-inf", bsize_int) == 0);
+       assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
+ 
+       n = vim_snprintf(buf, bsize, "%f", -0.0);
+       assert(n == 9);
+       assert(bsize == 0 || STRNCMP(buf, "-0.000000", bsize_int) == 0);
+       assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
+ #endif
+ 
+       n = vim_snprintf(buf, bsize, "%s", "漢語");
+       assert(n == 6);
+       assert(bsize == 0 || STRNCMP(buf, "漢語", bsize_int) == 0);
+       assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
+ 
+       n = vim_snprintf(buf, bsize, "%8s", "漢語");
+       assert(n == 8);
+       assert(bsize == 0 || STRNCMP(buf, "  漢語", bsize_int) == 0);
+       assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
+ 
+       n = vim_snprintf(buf, bsize, "%-8s", "漢語");
+       assert(n == 8);
+       assert(bsize == 0 || STRNCMP(buf, "漢語  ", bsize_int) == 0);
+       assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
+ 
+       n = vim_snprintf(buf, bsize, "%.3s", "漢語");
+       assert(n == 3);
+       assert(bsize == 0 || STRNCMP(buf, "漢", bsize_int) == 0);
+       assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
+ 
+       n = vim_snprintf(buf, bsize, fmt_5S, "foo");
+       assert(n == 5);
+       assert(bsize == 0 || STRNCMP(buf, "  foo", bsize_int) == 0);
+       assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
+ 
+       n = vim_snprintf(buf, bsize, "%%%%%%");
+       assert(n == 3);
+       assert(bsize == 0 || STRNCMP(buf, "%%%", bsize_int) == 0);
+       assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
+ 
+       n = vim_snprintf(buf, bsize, "%c%c", 1, 2);
+       assert(n == 2);
+       assert(bsize == 0 || STRNCMP(buf, "\x01\x02", bsize_int) == 0);
+       assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
+ 
+       // %p format is not tested in vim script tests Test_printf*()
+       // as it only makes sense in C code.
+       n = vim_snprintf(buf, bsize, "%p", ptr);
+       assert(n == 10);
+       assert(bsize == 0 || STRNCMP(buf, "0x87654321", bsize_int) == 0);
+       assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
+ 
+       n = vim_snprintf(buf, bsize, fmt_012p, ptr);
+       assert(n == 12);
+       assert(bsize == 0 || STRNCMP(buf, "0x0087654321", bsize_int) == 0);
+       assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0');
+ 
+       free(buf);
+     }
+ }
+ 
      int
  main(int argc, char **argv)
  {
***************
*** 104,113 ****
--- 265,276 ----
      set_option_value((char_u *)"encoding", 0, (char_u *)"utf-8", 0);
      init_chartab();
      test_trunc_string();
+     test_vim_snprintf();
  
      set_option_value((char_u *)"encoding", 0, (char_u *)"latin1", 0);
      init_chartab();
      test_trunc_string();
+     test_vim_snprintf();
  
      return 0;
  }
*** ../vim-8.2.0065/src/version.c       2019-12-30 22:33:14.137783570 +0100
--- src/version.c       2019-12-31 19:16:55.166610195 +0100
***************
*** 744,745 ****
--- 744,747 ----
  {   /* Add new patch number below this line */
+ /**/
+     66,
  /**/

-- 
There are three kinds of people: Those who can count & those who can't.

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/201912311825.xBVIPnGS011548%40masaka.moolenaar.net.

Raspunde prin e-mail lui