mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 03:52:35 +01:00
correct truncation in my_vsnprintf %M format
(because of a width or a short buffer)
This commit is contained in:
parent
76d8a43e34
commit
3f1290340e
2 changed files with 51 additions and 79 deletions
|
@ -153,7 +153,7 @@ static const char *check_longlong(const char *fmt, uint *have_longlong)
|
||||||
position in buffer which points on the end of escaped string
|
position in buffer which points on the end of escaped string
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static char *backtick_string(CHARSET_INFO *cs, char *to, char *end,
|
static char *backtick_string(CHARSET_INFO *cs, char *to, const char *end,
|
||||||
char *par, size_t par_len, char quote_char)
|
char *par, size_t par_len, char quote_char)
|
||||||
{
|
{
|
||||||
uint char_len;
|
uint char_len;
|
||||||
|
@ -196,7 +196,7 @@ err:
|
||||||
Prints string argument
|
Prints string argument
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static char *process_str_arg(CHARSET_INFO *cs, char *to, char *end,
|
static char *process_str_arg(CHARSET_INFO *cs, char *to, const char *end,
|
||||||
size_t width, char *par, uint print_type)
|
size_t width, char *par, uint print_type)
|
||||||
{
|
{
|
||||||
int well_formed_error;
|
int well_formed_error;
|
||||||
|
@ -257,7 +257,7 @@ static char *process_dbl_arg(char *to, char *end, size_t width,
|
||||||
Prints integer argument
|
Prints integer argument
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static char *process_int_arg(char *to, char *end, size_t length,
|
static char *process_int_arg(char *to, const char *end, size_t length,
|
||||||
longlong par, char arg_type, uint print_type)
|
longlong par, char arg_type, uint print_type)
|
||||||
{
|
{
|
||||||
size_t res_length, to_length;
|
size_t res_length, to_length;
|
||||||
|
@ -482,24 +482,26 @@ start:
|
||||||
case 'M':
|
case 'M':
|
||||||
{
|
{
|
||||||
longlong larg;
|
longlong larg;
|
||||||
char *org_to= to;
|
const char *real_end;
|
||||||
char errmsg_buff[MYSYS_STRERROR_SIZE];
|
|
||||||
|
|
||||||
length= (print_arr[i].flags & WIDTH_ARG)
|
width= (print_arr[i].flags & WIDTH_ARG)
|
||||||
? (size_t)args_arr[print_arr[i].width].longlong_arg
|
? (size_t)args_arr[print_arr[i].width].longlong_arg
|
||||||
: print_arr[i].width;
|
: print_arr[i].width;
|
||||||
|
|
||||||
|
real_end= MY_MIN(to + width, end);
|
||||||
|
|
||||||
larg = args_arr[print_arr[i].arg_idx].longlong_arg;
|
larg = args_arr[print_arr[i].arg_idx].longlong_arg;
|
||||||
to= process_int_arg(to, end, 0, larg, 'd', print_arr[i].flags);
|
to= process_int_arg(to, real_end, 0, larg, 'd', print_arr[i].flags);
|
||||||
width-= (to - org_to);
|
if (real_end - to >= 3)
|
||||||
if (width <= 4)
|
{
|
||||||
break;
|
char errmsg_buff[MYSYS_STRERROR_SIZE];
|
||||||
*to++= ' ';
|
*to++= ' ';
|
||||||
*to++= '"';
|
*to++= '"';
|
||||||
my_strerror(errmsg_buff, sizeof(errmsg_buff), (int) larg);
|
my_strerror(errmsg_buff, sizeof(errmsg_buff), larg);
|
||||||
to= process_str_arg(cs, to, end, width-3, errmsg_buff,
|
to= process_str_arg(cs, to, real_end, width, errmsg_buff,
|
||||||
print_arr[i].flags);
|
print_arr[i].flags);
|
||||||
*to++= '"';
|
if (real_end > to) *to++= '"';
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -666,18 +668,18 @@ size_t my_vsnprintf_ex(CHARSET_INFO *cs, char *to, size_t n,
|
||||||
}
|
}
|
||||||
else if (*fmt == 'M')
|
else if (*fmt == 'M')
|
||||||
{
|
{
|
||||||
const char *org_to= to;
|
|
||||||
int larg= va_arg(ap, int);
|
int larg= va_arg(ap, int);
|
||||||
to= process_int_arg(to, end, 0, larg, 'd', print_type);
|
const char *real_end= MY_MIN(to + width, end);
|
||||||
width-= (to - org_to);
|
|
||||||
if ((end - to) >= 4 && (int) width >= 4)
|
to= process_int_arg(to, real_end, 0, larg, 'd', print_type);
|
||||||
|
if (real_end - to >= 3)
|
||||||
{
|
{
|
||||||
char errmsg_buff[MYSYS_STRERROR_SIZE];
|
char errmsg_buff[MYSYS_STRERROR_SIZE];
|
||||||
*to++= ' ';
|
*to++= ' ';
|
||||||
*to++= '"';
|
*to++= '"';
|
||||||
my_strerror(errmsg_buff, sizeof(errmsg_buff), larg);
|
my_strerror(errmsg_buff, sizeof(errmsg_buff), larg);
|
||||||
to= process_str_arg(cs, to, end, width-3, errmsg_buff, print_type);
|
to= process_str_arg(cs, to, real_end, width, errmsg_buff, print_type);
|
||||||
*to++= '"';
|
if (real_end > to) *to++= '"';
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,16 @@
|
||||||
|
|
||||||
char buf[1024]; /* let's hope that's enough */
|
char buf[1024]; /* let's hope that's enough */
|
||||||
|
|
||||||
|
static void test_w_len(const char *res, size_t buflen, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
size_t len;
|
||||||
|
va_start(args,fmt);
|
||||||
|
len= my_vsnprintf(buf, buflen, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
ok(strlen(res) == len && strcmp(buf, res) == 0, "\"%s\"", buf);
|
||||||
|
}
|
||||||
|
|
||||||
static void test1(const char *res, const char *fmt, ...)
|
static void test1(const char *res, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
|
@ -51,7 +61,7 @@ static void test_many(const char **res, const char *fmt, ...)
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
plan(59);
|
plan(39);
|
||||||
|
|
||||||
test1("Constant string",
|
test1("Constant string",
|
||||||
"Constant string");
|
"Constant string");
|
||||||
|
@ -141,62 +151,6 @@ int main(void)
|
||||||
test1("G with a width (ignored) and precision: <12.35>",
|
test1("G with a width (ignored) and precision: <12.35>",
|
||||||
"G with a width (ignored) and precision: <%10.5g>", 12.3456789);
|
"G with a width (ignored) and precision: <%10.5g>", 12.3456789);
|
||||||
|
|
||||||
diag("================================================================");
|
|
||||||
|
|
||||||
test1("Hello",
|
|
||||||
"Hello");
|
|
||||||
test1("Hello int, 1",
|
|
||||||
"Hello int, %d", 1);
|
|
||||||
test1("Hello int, -1",
|
|
||||||
"Hello int, %d", -1);
|
|
||||||
test1("Hello int, 1",
|
|
||||||
"Hello int, %i", 1);
|
|
||||||
test1("Hello int, -1",
|
|
||||||
"Hello int, %i", -1);
|
|
||||||
test1("Hello string 'I am a string'",
|
|
||||||
"Hello string '%s'", "I am a string");
|
|
||||||
test1("Hello hack hack hack hack hack hack hack 1",
|
|
||||||
"Hello hack hack hack hack hack hack hack %d", 1);
|
|
||||||
test1("Hello 1 hack 4",
|
|
||||||
"Hello %d hack %d", 1, 4);
|
|
||||||
test1("Hello 1 hack hack hack hack hack 4",
|
|
||||||
"Hello %d hack hack hack hack hack %d", 1, 4);
|
|
||||||
test1("Hello 'hack' hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh",
|
|
||||||
"Hello '%s' hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh", "hack");
|
|
||||||
test1("Hello hhhhhhhhhhhhhh 1 sssssssssssssss",
|
|
||||||
"Hello hhhhhhhhhhhhhh %d sssssssssssssss", 1);
|
|
||||||
test1("Hello 1",
|
|
||||||
"Hello %u", 1);
|
|
||||||
test1("Hello 4294967295",
|
|
||||||
"Hello %u", -1);
|
|
||||||
test1("Hex: 20 ' 41'",
|
|
||||||
"Hex: %lx '%6lx'", 32, 65);
|
|
||||||
test1("conn 1 to: '(null)' user: '(null)' host: '(null)' ((null))",
|
|
||||||
"conn %ld to: '%-.64s' user: '%-.32s' host: '%-.64s' (%-.64s)",
|
|
||||||
1L, NULL, NULL, NULL, NULL);
|
|
||||||
test1("Hello string `I am a string`",
|
|
||||||
"Hello string %`s", "I am a string");
|
|
||||||
test1("Hello TEST",
|
|
||||||
"Hello %05s", "TEST");
|
|
||||||
test1("My `Q` test",
|
|
||||||
"My %1$`-.1s test", "QQQQ");
|
|
||||||
test1("My AAAA test done DDDD",
|
|
||||||
"My %2$s test done %1$s", "DDDD", "AAAA");
|
|
||||||
test1("My DDDD test CCCC, DDD",
|
|
||||||
"My %1$s test %2$s, %1$-.3s", "DDDD", "CCCC");
|
|
||||||
test1("My QQQQ test",
|
|
||||||
"My %1$`-.4b test", "QQQQ");
|
|
||||||
test1("My X test",
|
|
||||||
"My %1$c test", 'X');
|
|
||||||
test1("My <0000000010> test1 < a> test2 < A>",
|
|
||||||
"My <%010d> test1 <%4x> test2 <%4X>", 10, 10, 10);
|
|
||||||
test1("My <0000000010> test1 < a> test2 < a>",
|
|
||||||
"My <%1$010d> test1 <%2$4x> test2 <%2$4x>", 10, 10);
|
|
||||||
test1("My 00010 test",
|
|
||||||
"My %1$*02$d test", 10, 5);
|
|
||||||
test1("My `DDDD` test CCCC, `DDD`",
|
|
||||||
"My %1$`s test %2$s, %1$`-.3s", "DDDD", "CCCC");
|
|
||||||
|
|
||||||
{
|
{
|
||||||
/* Test that %M works */
|
/* Test that %M works */
|
||||||
const char *results[]=
|
const char *results[]=
|
||||||
|
@ -208,6 +162,22 @@ int main(void)
|
||||||
test_many(results, "Error %M", 1);
|
test_many(results, "Error %M", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test1("M with 0 error code: 0 \"Internal error/check (Not system error)\"",
|
||||||
|
"M with 0 error code: %M", 0);
|
||||||
|
|
||||||
|
test1("M with positional: 0 \"Internal error/check (Not system error)\"",
|
||||||
|
"M with positional: %1$M", 0);
|
||||||
|
|
||||||
|
test1("M with width: 0 \"Internal error/ch",
|
||||||
|
"M with width: %.20M", 0);
|
||||||
|
test1("M with width positional: 0 \"Internal error/ch",
|
||||||
|
"M with width positional: %2$.*1$M", 20, 0);
|
||||||
|
|
||||||
|
test_w_len("M small buf: 0 \"In",
|
||||||
|
19, "M small buf: %M", 0);
|
||||||
|
test_w_len("M small buf positional: 0 \"In",
|
||||||
|
30, "M small buf positional: %1$M", 0);
|
||||||
|
|
||||||
return exit_status();
|
return exit_status();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue