diff --git a/libc-test/src/functionalext/supplement/stdio/vsnprintf.c b/libc-test/src/functionalext/supplement/stdio/vsnprintf.c index 22eba6b5c27662794cceea01b64a10207c3c9063..0eec7fb3a2c7abdfa6e02b76c20aab62c0792047 100644 --- a/libc-test/src/functionalext/supplement/stdio/vsnprintf.c +++ b/libc-test/src/functionalext/supplement/stdio/vsnprintf.c @@ -18,6 +18,7 @@ #include #include #include "test.h" +#include "functionalext.h" void vsnprintf_test(char *str, size_t n, char *fmt, const char *func_name, ...) { @@ -49,6 +50,14 @@ void vsnprintf_zeron(char *str, char *fmt, const char *func_name, ...) } } +void vsnprintf_zeron_all(char *str, char *fmt, const char *func_name, ...) { + va_list ap; + va_start(ap, func_name); + int result = vsnprintf(0, 0, fmt, ap); + va_end(ap); + EXPECT_EQ(func_name, result, strlen(str)); +} + int main(int argc, char *argv[]) { /** @@ -75,5 +84,18 @@ int main(int argc, char *argv[]) * @tc.level : Level 2 */ vsnprintf_zeron("value is use", "value is %s", "vsnprintf_0400", "use"); + /** + * @tc.name : vsnprintf_0500 + * @tc.desc : truncate buffer, and bits to 0 + * @tc.level : Level 3 + */ + vsnprintf_zeron_all("value is use", "value is %s", "vsnprintf_0500", "use"); + /** + * @tc.name : vsnprintf_0600 + * @tc.desc : The number of bits to be 1 + * @tc.level : Level 2 + */ + vsnprintf_test("", 1, "value is %s", "vsnprintf_0600", "use"); + return t_status; -} \ No newline at end of file +} diff --git a/libc-test/src/functionalext/supplement/stdio/vsprintf.c b/libc-test/src/functionalext/supplement/stdio/vsprintf.c index c83130c68f9eda26b0048ade0b058d2a16ce423e..a8184294a7ea9577ee8bfff0b40e7dfc1ec6a462 100644 --- a/libc-test/src/functionalext/supplement/stdio/vsprintf.c +++ b/libc-test/src/functionalext/supplement/stdio/vsprintf.c @@ -25,7 +25,7 @@ */ void vsprintf_0100(char *format, ...) { - char buffer[20]; + char buffer[20] = {0}; va_list aptr; va_start(aptr, format); int result = vsprintf(buffer, format, aptr); @@ -34,7 +34,7 @@ void vsprintf_0100(char *format, ...) t_error("%s vsprintf get result is less than 0", __func__); } if (strcmp(buffer, "1")) { - t_error("%s wrong string written to buf", __func__); + t_error("%s wrong string written to buf %s\n", __func__, buffer); } } @@ -45,16 +45,16 @@ void vsprintf_0100(char *format, ...) */ void vsprintf_0200(char *format, ...) { - char buffer[20]; + char buffer[20] = {0}; va_list aptr; va_start(aptr, format); int result = vsprintf(buffer, format, aptr); va_end(aptr); if (result < 0) { - t_error("%s vsprintf get result is less than 0", __func__); + t_error("%s vsprintf get result is less than 0\n", __func__); } if (strncmp(buffer, "3.0", 3)) { - t_error("%s wrong string written to buf", __func__); + t_error("%s wrong string written to buf %s\n", __func__, buffer); } } @@ -71,10 +71,10 @@ void vsprintf_0300(char *format, ...) int result = vsprintf(buffer, format, aptr); va_end(aptr); if (result < 0) { - t_error("%s vsprintf get result is less than 0", __func__); + t_error("%s vsprintf get result is less than 0\n", __func__); } if (strcmp(buffer, "vsprintf test")) { - t_error("%s wrong string written to buf", __func__); + t_error("%s wrong string written to buf %s\n", __func__, buffer); } } @@ -87,4 +87,4 @@ int main(int argc, char *argv[]) vsprintf_0200("%f", f); vsprintf_0300("%s", str); return t_status; -} \ No newline at end of file +} diff --git a/musl_src.gni b/musl_src.gni index 68987ebdbf60bc8a18bc64af5354a48fd0bfc3ca..67a7b3296213ad8b0a1acff5849c2b698abe77ec 100644 --- a/musl_src.gni +++ b/musl_src.gni @@ -2188,6 +2188,7 @@ musl_src_porting_file = [ "src/stdio/__towrite.c", "src/stdio/stderr.c", "src/stdio/fgets.c", + "src/stdio/vsnprintf.c", "src/internal/stdio_impl.h", "src/internal/vdso.c", "src/time/clock_gettime.c", diff --git a/porting/linux/user/src/internal/stdio_impl.h b/porting/linux/user/src/internal/stdio_impl.h index 3fec9b2c18b89f42e628f5ae47844dadebbd4629..055c9f5777b3229ddb65b347d73bd6fcf66f79e2 100644 --- a/porting/linux/user/src/internal/stdio_impl.h +++ b/porting/linux/user/src/internal/stdio_impl.h @@ -18,6 +18,7 @@ #define F_SVB 64 #define F_APP 128 #define F_NOBUF 256 +#define F_PBUF 512 struct _IO_FILE { unsigned flags; diff --git a/porting/linux/user/src/stdio/vfprintf.c b/porting/linux/user/src/stdio/vfprintf.c index 4cdc99c046a18b393a85f57eec4ee36c4d77bc7c..b176aa482bc2f68c9098736620931f26569d6553 100644 --- a/porting/linux/user/src/stdio/vfprintf.c +++ b/porting/linux/user/src/stdio/vfprintf.c @@ -132,7 +132,14 @@ static void pop_arg(union arg *arg, int type, va_list *ap) static void out(FILE *f, const char *s, size_t l) { - if (!(f->flags & F_ERR)) __fwritex((void *)s, l, f); + /* write to file buffer if flag F_PBUF is available */ + if (!(f->flags & F_ERR) && !(f->flags & F_PBUF)) { + __fwritex((void *)s, l, f); + return; + } + + /* otherwise, copy to buffer directly */ + f->write(f, (void *)s, l); } static void pad(FILE *f, char c, int w, int l, int fl) @@ -675,13 +682,7 @@ int vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap) olderr = f->flags & F_ERR; if (f->mode < 1) f->flags &= ~F_ERR; - /* allocate file buffer if need */ - if (__falloc_buf(f) < 0) { - f->flags |= F_ERR; - ret = -1; - } - - if (!f->buf_size) { + if (!f->buf_size && f->buf != NULL) { saved_buf = f->buf; f->buf = internal_buf; f->buf_size = sizeof internal_buf; @@ -690,7 +691,9 @@ int vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap) if (!f->wend && __towrite(f)) ret = -1; else ret = printf_core(f, fmt, &ap2, nl_arg, nl_type, 0); if (saved_buf) { - f->write(f, 0, 0); + if (!(f->flags & F_PBUF)) { + f->write(f, 0, 0); + } if (!f->wpos) ret = -1; f->buf = saved_buf; f->buf_size = 0; diff --git a/porting/linux/user/src/stdio/vsnprintf.c b/porting/linux/user/src/stdio/vsnprintf.c new file mode 100644 index 0000000000000000000000000000000000000000..6a1ce879a5acdd28d4672b83152dc570553f5258 --- /dev/null +++ b/porting/linux/user/src/stdio/vsnprintf.c @@ -0,0 +1,47 @@ +#include "stdio_impl.h" +#include +#include +#include +#include + +struct cookie { + char *s; + size_t n; +}; + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +static size_t sn_write(FILE *f, const unsigned char *s, size_t l) { + struct cookie *c = f->cookie; + size_t already_size = f->wpos - f->wbase; + if (already_size <= c->n) { + size_t k = MIN(l, c->n - already_size); + memcpy(f->wpos, s, k); + f->wpos += k; + *f->wpos = '\0'; + } + /* pretend to succeed, even if we discarded extra data */ + return l; +} + +int vsnprintf(char *restrict s, size_t n, const char *restrict fmt, va_list ap) +{ + unsigned char dummy[1]; + struct cookie c = { .s = n ? s : dummy, .n = n ? n-1 : 0 }; + FILE f = { + .lbf = EOF, + .lock = -1, + .buf = (unsigned char *)(n ? s: dummy), + .buf_size = n ? n - 1 : 0, + .flags = F_PBUF, + .cookie = &c, + .write = sn_write, + }; + + if (n > INT_MAX) { + errno = EOVERFLOW; + return -1; + } + + return vfprintf(&f, fmt, ap); +}