diff --git a/system/lib/libc/README.md b/system/lib/libc/README.md index f63b1e1752c90..7a09856ff35fe 100644 --- a/system/lib/libc/README.md +++ b/system/lib/libc/README.md @@ -1,4 +1,5 @@ -This folder contains the musl version of libc at `/musl`. The upstream version can be found at http://www.musl-libc.org/ +This folder contains the musl version of libc at `/musl`. The upstream version can be found at http://www.musl-libc.org/. +Most of the source comes from musl 1.1.15, with some exceptions listed below. Some changes have been made to the version that was taken from upstream, including: @@ -8,3 +9,4 @@ Some changes have been made to the version that was taken from upstream, includi * Simplify stdout stream handling: do not support seeking, terminal handling, etc., as it just increases code size and Emscripten doesn't have those features anyhow. * Setting `_POSIX_REALTIME_SIGNALS` and `_POSIX_SPAWN` macros to -1, to exclude unsupported functions. +Backported src/stdio/vswprintf.c from 1.1.23 to fix #9305. diff --git a/system/lib/libc/musl/src/stdio/vswprintf.c b/system/lib/libc/musl/src/stdio/vswprintf.c index 7d237bae72e94..7f98c5c9690e4 100644 --- a/system/lib/libc/musl/src/stdio/vswprintf.c +++ b/system/lib/libc/musl/src/stdio/vswprintf.c @@ -1,8 +1,8 @@ #include "stdio_impl.h" #include -#include #include #include +#include #include struct cookie { @@ -24,23 +24,30 @@ static size_t sw_write(FILE *f, const unsigned char *s, size_t l) c->ws++; } *c->ws = 0; - return i<0 ? i : l0; + if (i < 0) { + f->wpos = f->wbase = f->wend = 0; + f->flags |= F_ERR; + return i; + } + f->wend = f->buf + f->buf_size; + f->wpos = f->wbase = f->buf; + return l0; } int vswprintf(wchar_t *restrict s, size_t n, const wchar_t *restrict fmt, va_list ap) { int r; - FILE f; unsigned char buf[256]; struct cookie c = { s, n-1 }; + FILE f = { + .lbf = EOF, + .write = sw_write, + .lock = -1, + .buf = buf, + .buf_size = sizeof buf, + .cookie = &c, + }; - memset(&f, 0, sizeof(FILE)); - f.lbf = EOF; - f.write = sw_write; - f.buf_size = sizeof buf; - f.buf = buf; - f.lock = -1; - f.cookie = &c; if (!n) { return -1; } else if (n > INT_MAX) { diff --git a/tests/core/test_wprintf.cpp b/tests/core/test_wprintf.cpp index 5e9185241918d..8b40a47b1f7a3 100644 --- a/tests/core/test_wprintf.cpp +++ b/tests/core/test_wprintf.cpp @@ -8,16 +8,19 @@ #include #include +#define MAX_CHARS_SMALL 256 +#define MAX_CHARS_BIG 8096 + void PrintWide ( const wchar_t * format, ... ) { - wchar_t buffer[256]; - memset(buffer, 0, 256); + wchar_t buffer[MAX_CHARS_SMALL]; + memset(buffer, 0, MAX_CHARS_SMALL); va_list args; va_start ( args, format ); wprintf(L"format starts with 0x%x\n", *(int*)format); wprintf(L"fmt continues with 0x%x\n", *(((int*)format) + 1)); wprintf(L"fmt continues with 0x%x\n", *(((int*)format) + 2)); - int r = vswprintf ( buffer, 256, format, args ); + int r = vswprintf ( buffer, MAX_CHARS_SMALL-1, format, args ); wprintf(L"vswprintf told us %d\n", r); wprintf(L"vswoutput st-rts with 0x%x\n", *(int*)buffer); wprintf(L"vsw continues with 0x%x\n", *(((int*)buffer) + 1)); @@ -26,6 +29,17 @@ void PrintWide ( const wchar_t * format, ... ) va_end ( args ); } +void PrintBigWide ( const wchar_t * format, ... ) +{ + wchar_t buffer[MAX_CHARS_BIG] = { 0 }; + va_list args; + va_start ( args, format ); + int ret = vswprintf ( buffer, MAX_CHARS_BIG-1, format, args ); + va_end ( args ); + wprintf(L"PrintBigWide wrote %d wchars:\n", ret); + wprintf(buffer); +} + int main () { FILE *f = fopen("test.dat", "wb"); @@ -45,7 +59,15 @@ int main () PrintWide ( str, wcslen(str) ); PrintWide ( str, wcslen(str) ); PrintWide ( str, wcslen(str) ); - + + + wchar_t long_str[] = L"test string has %d wide characters.\n" + "Internally the variadic print functions use a 256 char buffer, so this is a string that's longer than 256 chars, " + "so in case this breaks we have a test case. As discovered in #9305 vswprintf had been broken for some time, " + "but was never picked up as the test strings were all shorter then 256 chars. So hopefully this long rambly string " + "will help guard against that bug being re-introduced.\n"; + PrintBigWide ( long_str, wcslen(long_str) ); + wprintf (L"Characters: %lc %lc \n", L'a', 65); wprintf (L"Decimals: %d %ld\n", 1977, 650000L); wprintf (L"Preceding with blanks: %10d \n", 1977); diff --git a/tests/core/test_wprintf.out b/tests/core/test_wprintf.out index 8dfed67acfeb6..44fee7f77c69d 100644 --- a/tests/core/test_wprintf.out +++ b/tests/core/test_wprintf.out @@ -27,6 +27,9 @@ vswoutput st-rts with 0x74 vsw continues with 0x65 vsw continues with 0x73 test string has 36 wide characters. +PrintBigWide wrote 426 wchars: +test string has 425 wide characters. +Internally the variadic print functions use a 256 char buffer, so this is a string that's longer than 256 chars, so in case this breaks we have a test case. As discovered in #9305 vswprintf had been broken for some time, but was never picked up as the test strings were all shorter then 256 chars. So hopefully this long rambly string will help guard against that bug being re-introduced. Characters: a A Decimals: 1977 650000 Preceding with blanks: 1977