curlx: add local snprintf() helper that always nul-terminates (Windows)

Make the helper use `vsnprintf()` internally on all supported Windows
toolchains (dropping `_snprintf()` and `snprintf()`), ensure to
nul-terminate. Omit the return value to avoid complexity.

Use the helper from `mprintf.c` / `out_double()`, from tests/server code
and the tests/server-specific build of `curlx_inet_ntop()`,
`curlx_strerror()` functions. In the single call (in tests) where the
returned length was used previously, determine it with `strlen()`.

Refs:
https://github.com/libssh2/libssh2/blob/libssh2-1.11.1/src/misc.c#L57-L79
https://learn.microsoft.com/cpp/c-runtime-library/reference/snprintf-snprintf-snprintf-l-snwprintf-snwprintf-l
https://learn.microsoft.com/cpp/c-runtime-library/reference/vsnprintf-vsnprintf-vsnprintf-l-vsnwprintf-vsnwprintf-l

Assisted-by: Jay Satiro
Follow-up to fa8bd1cc09 #20761
Follow-up to 8ab468c8aa #15997

Closes #20765
This commit is contained in:
Viktor Szakats 2026-02-27 16:43:16 +01:00
parent b83ade783d
commit 64f28b8f88
No known key found for this signature in database
8 changed files with 76 additions and 20 deletions

View file

@ -26,6 +26,7 @@
#include "curlx/dynbuf.h"
#include "curl_printf.h"
#include "curlx/strparse.h"
#include "curlx/snprintf.h" /* for curlx_win32_snprintf() */
#define BUFFSIZE 326 /* buffer for long-to-str and float-to-str calcs, should
fit negative DBL_MAX (317 letters) */
@ -671,29 +672,23 @@ static bool out_double(void *userp,
/* NOTE NOTE NOTE!! Not all sprintf implementations return number of
output characters */
#ifdef HAVE_SNPRINTF
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
#endif
#ifdef _WIN32
curlx_win32_snprintf(work, BUFFSIZE, formatbuf, dnum);
#elif defined(HAVE_SNPRINTF)
/* !checksrc! disable BANNEDFUNC 1 */
/* !checksrc! disable LONGLINE */
/* NOLINTNEXTLINE(clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling) */
snprintf(work, BUFFSIZE, formatbuf, dnum);
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
#ifdef _WIN32
/* Old versions of the Windows CRT do not terminate the snprintf output
buffer if it reaches the max size so we do that here. */
work[BUFFSIZE - 1] = 0;
#endif
#elif defined(_MSC_VER) && (_MSC_VER < 1900)
_snprintf(work, BUFFSIZE, formatbuf, dnum);
work[BUFFSIZE - 1] = 0;
#else
/* float and double outputs do not work without snprintf support */
work[0] = 0;
#endif
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
DEBUGASSERT(strlen(work) < BUFFSIZE);
while(*work) {