mirror of
https://github.com/curl/curl.git
synced 2026-08-03 20:30:36 +03:00
mprintf: Fix processing of width and prec args
Prior to this change a width arg could be erroneously output, and also width and precision args could not be used together without crashing. "%0*d%s", 2, 9, "foo" Before: "092" After: "09foo" "%*.*s", 5, 2, "foo" Before: crash After: " fo" Test 557 is updated to verify this and more
This commit is contained in:
parent
117a0ffe9f
commit
68701e51c1
3 changed files with 90 additions and 20 deletions
|
|
@ -460,22 +460,24 @@ static long dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos,
|
||||||
if(flags & FLAGS_WIDTHPARAM) {
|
if(flags & FLAGS_WIDTHPARAM) {
|
||||||
/* we have the width specified from a parameter, so we make that
|
/* we have the width specified from a parameter, so we make that
|
||||||
parameter's info setup properly */
|
parameter's info setup properly */
|
||||||
vto[i].width = width - 1;
|
long k = width - 1;
|
||||||
i = width - 1;
|
vto[i].width = k;
|
||||||
vto[i].type = FORMAT_WIDTH;
|
vto[k].type = FORMAT_WIDTH;
|
||||||
vto[i].flags = FLAGS_NEW;
|
vto[k].flags = FLAGS_NEW;
|
||||||
vto[i].precision = vto[i].width = 0; /* can't use width or precision
|
/* can't use width or precision of width! */
|
||||||
of width! */
|
vto[k].width = 0;
|
||||||
|
vto[k].precision = 0;
|
||||||
}
|
}
|
||||||
if(flags & FLAGS_PRECPARAM) {
|
if(flags & FLAGS_PRECPARAM) {
|
||||||
/* we have the precision specified from a parameter, so we make that
|
/* we have the precision specified from a parameter, so we make that
|
||||||
parameter's info setup properly */
|
parameter's info setup properly */
|
||||||
vto[i].precision = precision - 1;
|
long k = precision - 1;
|
||||||
i = precision - 1;
|
vto[i].precision = k;
|
||||||
vto[i].type = FORMAT_WIDTH;
|
vto[k].type = FORMAT_WIDTH;
|
||||||
vto[i].flags = FLAGS_NEW;
|
vto[k].flags = FLAGS_NEW;
|
||||||
vto[i].precision = vto[i].width = 0; /* can't use width or precision
|
/* can't use width or precision of width! */
|
||||||
of width! */
|
vto[k].width = 0;
|
||||||
|
vto[k].precision = 0;
|
||||||
}
|
}
|
||||||
*endpos++ = fmt + 1; /* end of this sequence */
|
*endpos++ = fmt + 1; /* end of this sequence */
|
||||||
}
|
}
|
||||||
|
|
@ -483,11 +485,15 @@ static long dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos,
|
||||||
|
|
||||||
/* Read the arg list parameters into our data list */
|
/* Read the arg list parameters into our data list */
|
||||||
for(i=0; i<max_param; i++) {
|
for(i=0; i<max_param; i++) {
|
||||||
if((i + 1 < max_param) && (vto[i + 1].type == FORMAT_WIDTH)) {
|
/* Width/precision arguments must be read before the main argument
|
||||||
/* Width/precision arguments must be read before the main argument
|
they are attached to */
|
||||||
* they are attached to
|
if(vto[i].flags & FLAGS_WIDTHPARAM) {
|
||||||
*/
|
vto[vto[i].width].data.num.as_signed =
|
||||||
vto[i + 1].data.num.as_signed = (mp_intmax_t)va_arg(arglist, int);
|
(mp_intmax_t)va_arg(arglist, int);
|
||||||
|
}
|
||||||
|
if(vto[i].flags & FLAGS_PRECPARAM) {
|
||||||
|
vto[vto[i].precision].data.num.as_signed =
|
||||||
|
(mp_intmax_t)va_arg(arglist, int);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (vto[i].type) {
|
switch (vto[i].type) {
|
||||||
|
|
@ -640,16 +646,30 @@ static int dprintf_formatf(
|
||||||
p = &vto[param];
|
p = &vto[param];
|
||||||
|
|
||||||
/* pick up the specified width */
|
/* pick up the specified width */
|
||||||
if(p->flags & FLAGS_WIDTHPARAM)
|
if(p->flags & FLAGS_WIDTHPARAM) {
|
||||||
width = (long)vto[p->width].data.num.as_signed;
|
width = (long)vto[p->width].data.num.as_signed;
|
||||||
|
param_num++; /* since the width is extracted from a parameter, we
|
||||||
|
must skip that to get to the next one properly */
|
||||||
|
if(width < 0) {
|
||||||
|
/* "A negative field width is taken as a '-' flag followed by a
|
||||||
|
positive field width." */
|
||||||
|
width = -width;
|
||||||
|
p->flags |= FLAGS_LEFT;
|
||||||
|
p->flags &= ~FLAGS_PAD_NIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
width = p->width;
|
width = p->width;
|
||||||
|
|
||||||
/* pick up the specified precision */
|
/* pick up the specified precision */
|
||||||
if(p->flags & FLAGS_PRECPARAM) {
|
if(p->flags & FLAGS_PRECPARAM) {
|
||||||
prec = (long)vto[p->precision].data.num.as_signed;
|
prec = (long)vto[p->precision].data.num.as_signed;
|
||||||
param_num++; /* since the precision is extraced from a parameter, we
|
param_num++; /* since the precision is extracted from a parameter, we
|
||||||
must skip that to get to the next one properly */
|
must skip that to get to the next one properly */
|
||||||
|
if(prec < 0)
|
||||||
|
/* "A negative precision is taken as if the precision were
|
||||||
|
omitted." */
|
||||||
|
prec = -1;
|
||||||
}
|
}
|
||||||
else if(p->flags & FLAGS_PREC)
|
else if(p->flags & FLAGS_PREC)
|
||||||
prec = p->precision;
|
prec = p->precision;
|
||||||
|
|
@ -804,7 +824,7 @@ static int dprintf_formatf(
|
||||||
else
|
else
|
||||||
len = strlen(str);
|
len = strlen(str);
|
||||||
|
|
||||||
width -= (long)len;
|
width -= (len > LONG_MAX) ? LONG_MAX : (long)len;
|
||||||
|
|
||||||
if(p->flags & FLAGS_ALT)
|
if(p->flags & FLAGS_ALT)
|
||||||
OUTCHAR('"');
|
OUTCHAR('"');
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ All curl_mprintf() signed int tests OK!
|
||||||
All curl_mprintf() unsigned long tests OK!
|
All curl_mprintf() unsigned long tests OK!
|
||||||
All curl_mprintf() signed long tests OK!
|
All curl_mprintf() signed long tests OK!
|
||||||
All curl_mprintf() curl_off_t tests OK!
|
All curl_mprintf() curl_off_t tests OK!
|
||||||
|
All curl_mprintf() strings tests OK!
|
||||||
</stdout>
|
</stdout>
|
||||||
</verify>
|
</verify>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1374,6 +1374,53 @@ static int test_curl_off_t_formatting(void)
|
||||||
return failed;
|
return failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int string_check(char *buf, const char *buf2)
|
||||||
|
{
|
||||||
|
if(strcmp(buf, buf2)) {
|
||||||
|
/* they shouldn't differ */
|
||||||
|
printf("sprintf failed:\nwe '%s'\nsystem: '%s'\n",
|
||||||
|
buf, buf2);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The output strings in this test need to have been verified with a system
|
||||||
|
* sprintf() before used here.
|
||||||
|
*/
|
||||||
|
static int test_string_formatting(void)
|
||||||
|
{
|
||||||
|
int errors = 0;
|
||||||
|
char buf[256];
|
||||||
|
curl_msnprintf(buf, sizeof(buf), "%0*d%s", 2, 9, "foo");
|
||||||
|
errors += string_check(buf, "09foo");
|
||||||
|
|
||||||
|
curl_msnprintf(buf, sizeof(buf), "%*.*s", 5, 2, "foo");
|
||||||
|
errors += string_check(buf, " fo");
|
||||||
|
|
||||||
|
curl_msnprintf(buf, sizeof(buf), "%*.*s", 2, 5, "foo");
|
||||||
|
errors += string_check(buf, "foo");
|
||||||
|
|
||||||
|
curl_msnprintf(buf, sizeof(buf), "%*.*s", 0, 10, "foo");
|
||||||
|
errors += string_check(buf, "foo");
|
||||||
|
|
||||||
|
curl_msnprintf(buf, sizeof(buf), "%-10s", "foo");
|
||||||
|
errors += string_check(buf, "foo ");
|
||||||
|
|
||||||
|
curl_msnprintf(buf, sizeof(buf), "%10s", "foo");
|
||||||
|
errors += string_check(buf, " foo");
|
||||||
|
|
||||||
|
curl_msnprintf(buf, sizeof(buf), "%*.*s", -10, -10, "foo");
|
||||||
|
errors += string_check(buf, "foo ");
|
||||||
|
|
||||||
|
if(!errors)
|
||||||
|
printf("All curl_mprintf() strings tests OK!\n");
|
||||||
|
else
|
||||||
|
printf("Some curl_mprintf() string tests Failed!\n");
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
int test(char *URL)
|
int test(char *URL)
|
||||||
{
|
{
|
||||||
|
|
@ -1394,6 +1441,8 @@ int test(char *URL)
|
||||||
|
|
||||||
errors += test_curl_off_t_formatting();
|
errors += test_curl_off_t_formatting();
|
||||||
|
|
||||||
|
errors += test_string_formatting();
|
||||||
|
|
||||||
if(errors)
|
if(errors)
|
||||||
return TEST_ERR_MAJOR_BAD;
|
return TEST_ERR_MAJOR_BAD;
|
||||||
else
|
else
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue