diff --git a/lib/mprintf.c b/lib/mprintf.c index 1a40583c2f..61e352e65c 100644 --- a/lib/mprintf.c +++ b/lib/mprintf.c @@ -678,12 +678,12 @@ static int formatf( struct outsegment output[MAX_SEGMENTS]; struct va_input input[MAX_PARAMETERS]; - char work[BUFFSIZE]; + char work[BUFFSIZE + 2]; /* 'workend' points to the final buffer byte position, but with an extra byte as margin to avoid the (FALSE?) warning Coverity gives us otherwise */ - char *workend = &work[sizeof(work) - 2]; + char *workend = &work[BUFFSIZE - 2]; /* Parse the format string */ if(parsefmt(format, output, input, &ocount, &icount, ap_save)) @@ -966,8 +966,8 @@ number: if(width >= 0) { size_t dlen; - if(width >= (int)sizeof(work)) - width = sizeof(work)-1; + if(width >= BUFFSIZE) + width = BUFFSIZE - 1; /* RECURSIVE USAGE */ dlen = (size_t)curl_msnprintf(fptr, left, "%d", width); fptr += dlen; @@ -976,17 +976,19 @@ number: if(prec >= 0) { /* for each digit in the integer part, we can have one less precision */ - size_t maxprec = sizeof(work) - 2; + int maxprec = BUFFSIZE - 1; double val = iptr->val.dnum; + if(prec > maxprec) + prec = maxprec - 1; if(width > 0 && prec <= width) - maxprec -= (size_t)width; + maxprec -= width; while(val >= 10.0) { val /= 10; maxprec--; } - if(prec > (int)maxprec) - prec = (int)maxprec-1; + if(prec > maxprec) + prec = maxprec - 1; if(prec < 0) prec = 0; /* RECURSIVE USAGE */ @@ -1012,14 +1014,19 @@ number: /* NOTE NOTE NOTE!! Not all sprintf implementations return number of output characters */ #ifdef HAVE_SNPRINTF - (snprintf)(work, sizeof(work), formatbuf, iptr->val.dnum); /* NOLINT */ + (snprintf)(work, BUFFSIZE, formatbuf, iptr->val.dnum); /* NOLINT */ #else (sprintf)(work, formatbuf, iptr->val.dnum); #endif #ifdef __clang__ #pragma clang diagnostic pop #endif - DEBUGASSERT(strlen(work) <= sizeof(work)); + DEBUGASSERT(strlen(work) < BUFFSIZE); +#ifdef __MINGW32__ + /* Work-around for a nasty bug seen with old-mingw and gcc 7.3.0 when it + writes one byte more than permitted. */ + work[BUFFSIZE - 1] = 0; +#endif for(fptr = work; *fptr; fptr++) OUTCHAR(*fptr); break; diff --git a/tests/libtest/lib557.c b/tests/libtest/lib557.c index d84626036f..e0e7dfb36d 100644 --- a/tests/libtest/lib557.c +++ b/tests/libtest/lib557.c @@ -1207,6 +1207,46 @@ static int test_pos_arguments(void) return errors; } +static int test_width_precision(void) +{ + /* 325 is max precision (and width) for a double */ + char larger[1024]; +#define SPACE60 " " +#define SPACE300 SPACE60 SPACE60 SPACE60 SPACE60 SPACE60 +#define OK325 SPACE300 " 0" + + int rc; + int errors = 0; + rc = curl_msnprintf(larger, sizeof(larger), "%325.325f", 0.1); + if(rc != 325) + errors++; + errors += string_check(larger, OK325); + + rc = curl_msnprintf(larger, sizeof(larger), "%326.326f", 0.1); + if(rc != 325) + errors++; + errors += string_check(larger, OK325); + + rc = curl_msnprintf(larger, sizeof(larger), "%1000.1000f", 0.1); + if(rc != 325) + errors++; + errors += string_check(larger, OK325); + + rc = curl_msnprintf(larger, sizeof(larger), "%324.324f", 0.1); + if(rc != 324) + errors++; + rc = curl_msnprintf(larger, sizeof(larger), "%324.0f", 0.1); + if(rc != 324) + errors++; + rc = curl_msnprintf(larger, sizeof(larger), "%0.324f", 0.1); + if(rc != 325) + errors++; + + return errors; +} + + + static int test_weird_arguments(void) { int errors = 0; @@ -1320,6 +1360,8 @@ static int test_weird_arguments(void) errors += string_check(buf, ""); + errors += test_width_precision(); + if(errors) printf("Some curl_mprintf() weird arguments tests failed!\n");