From 9df2d784439720abbf67fa96c6515a5c4a9f230a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 14 Jan 2021 18:48:44 -0800 Subject: [PATCH 2/2] tinystdio: Fix snprintf(buf, 0, ...) to not smash buffer snprintf(buf, 0) should not write anything to the destination, not even a trailing '\0'. The tinystdio implementation had a signed comparison bug where this case would cause a null to be placed in the output buffer at the size of the data that would have been written. Add a test to make sure snprintf respects the 'len' parameter correctly. Signed-off-by: Keith Packard --- newlib/libc/tinystdio/snprintf.c | 2 +- test/printf_scanf.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) --- a/newlib/libc/tinystdio/snprintf.c +++ b/newlib/libc/tinystdio/snprintf.c @@ -56,7 +56,7 @@ i = vfprintf(&f.file, fmt, ap); va_end(ap); - if (n >= 0 && i >= 0) + if ((int) n >= 0 && i >= 0) s[i < n ? i : n] = 0; return i; --- a/test/printf_scanf.c +++ b/test/printf_scanf.c @@ -96,6 +96,37 @@ fflush(stdout); } #endif + + /* + * test snprintf to make sure it doesn't overwrite the specified buffer + * length (even if that is zero) + */ + for (x = 0; x <= 6; x++) { + char tbuf[10] = "xxxxxxxxx"; + const char ref[10] = "xxxxxxxxx"; + int i = snprintf(tbuf, x, "%s", "123"); + int y = x <= 4 ? x : 4; + if (i != 3) { + printf("snprintf(tbuf, %d, \"%%s\", \"123\") return %d instead of %d\n", + x, i, 3); + errors++; + } + int l = strlen(tbuf); + if (y > 0 && l != y - 1) { + printf("returned buffer len want %d got %d\n", y - 1, l); + errors++; + } + if (y > 0 && strncmp(tbuf, "123", y - 1) != 0) { + strncpy(buf, "123", y - 1); + buf[y-1] = '\0'; + printf("returned buffer want %s got %s\n", buf, tbuf); + errors++; + } + if (memcmp(tbuf + y, ref + y, sizeof(tbuf) - y) != 0) { + printf("tail of buf mangled %s\n", tbuf + y); + errors++; + } + } for (x = 0; x < 32; x++) { unsigned int v = 0x12345678 >> x; unsigned int r;