mirror of
https://github.com/vim/vim.git
synced 2025-09-26 04:04:07 -04:00
patch 8.2.0066: some corners of vim_snprintf() are not tested
Problem: Some corners of vim_snprintf() are not tested. Solution: Add a test in C. (Dominique Pelle, closes #5422)
This commit is contained in:
@@ -22,6 +22,24 @@
|
||||
// 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,6 +111,149 @@ test_trunc_string(void)
|
||||
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,10 +265,12 @@ main(int argc, char **argv)
|
||||
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;
|
||||
}
|
||||
|
@@ -742,6 +742,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
66,
|
||||
/**/
|
||||
65,
|
||||
/**/
|
||||
|
Reference in New Issue
Block a user