diff --git a/src/klibc/rt_vsnprintf_std.c b/src/klibc/rt_vsnprintf_std.c index 481c99013b00..24ff4c7ae3cf 100644 --- a/src/klibc/rt_vsnprintf_std.c +++ b/src/klibc/rt_vsnprintf_std.c @@ -371,7 +371,9 @@ static inline output_gadget_t buffer_gadget(char* buffer, size_t buffer_size) static inline printf_size_t strnlen_s_(const char* str, printf_size_t maxsize) { const char* s; - for (s = str; *s && maxsize--; ++s); + // check the bound before dereferencing, + // so that at most maxsize characters are read. + for (s = str; maxsize && *s; ++s, --maxsize); return (printf_size_t)(s - str); } @@ -1053,7 +1055,14 @@ static inline void format_string_loop(output_gadget_t* output, const char* forma } else if (*format == '*') { const int precision_ = va_arg(args, int); - precision = precision_ > 0 ? (printf_size_t) precision_ : 0U; + if (precision_ < 0) + { + flags &= ~FLAGS_PRECISION; + } + else + { + precision = (printf_size_t)precision_; + } ADVANCE_IN_FORMAT_STRING(format); } } diff --git a/src/klibc/rt_vsnprintf_tiny.c b/src/klibc/rt_vsnprintf_tiny.c index 36811048a993..750c916991df 100644 --- a/src/klibc/rt_vsnprintf_tiny.c +++ b/src/klibc/rt_vsnprintf_tiny.c @@ -83,6 +83,7 @@ static char *print_number(char *buf, static const char large_digits[] = "0123456789ABCDEF"; int i = 0; int size = 0; + int is_zero = 0; size = s; @@ -151,6 +152,7 @@ static char *print_number(char *buf, } i = 0; + is_zero = (num == 0); if (num == 0) { tmp[i++] = '0'; @@ -253,7 +255,7 @@ static char *print_number(char *buf, } /* put number in the temporary buffer */ - while (i-- > 0 && (precision_bak != 0)) + while (i-- > 0 && !((precision_bak == 0) && is_zero)) { if (buf < end) { @@ -382,8 +384,12 @@ int rt_vsnprintf(char *buf, size_t size, const char *fmt, va_list args) ++fmt; /* it's the next argument */ precision = va_arg(args, int); + if (precision < 0) + { + precision = -1; + } } - if (precision < 0) + else { precision = 0; } @@ -451,12 +457,7 @@ int rt_vsnprintf(char *buf, size_t size, const char *fmt, va_list args) s = "(null)"; } - for (len = 0; (len != field_width) && (s[len] != '\0'); len++); - - if (precision > 0 && len > precision) - { - len = precision; - } + for (len = 0; (precision < 0 || len < precision) && (s[len] != '\0'); len++); if (!(flags & LEFT)) { diff --git a/src/klibc/utest/TC_rt_sprintf.c b/src/klibc/utest/TC_rt_sprintf.c index d8bba42c08c8..1e9bf8449563 100644 --- a/src/klibc/utest/TC_rt_sprintf.c +++ b/src/klibc/utest/TC_rt_sprintf.c @@ -334,9 +334,7 @@ SPRINTF_TEST_CASE(specifier) SPRINTF_TEST_CASE(width) { char buffer[base_buffer_size]; -#ifdef RT_KLIBC_USING_VSNPRINTF_STANDARD SPRINTF_CHECK("Hello testing", buffer, "%1s", "Hello testing"); -#endif /* RT_KLIBC_USING_VSNPRINTF_STANDARD */ SPRINTF_CHECK("1024", buffer, "%1d", 1024); SPRINTF_CHECK("-1024", buffer, "%1d", -1024); SPRINTF_CHECK("1024", buffer, "%1i", 1024); @@ -837,10 +835,6 @@ SPRINTF_TEST_CASE(tiny_floating_point_values) SPRINTF_TEST_CASE(length) { char buffer[base_buffer_size]; - SPRINTF_CHECK("", buffer, "%.0s", "Hello testing"); - SPRINTF_CHECK(" ", buffer, "%20.0s", "Hello testing"); - SPRINTF_CHECK("", buffer, "%.s", "Hello testing"); - SPRINTF_CHECK(" ", buffer, "%20.s", "Hello testing"); SPRINTF_CHECK(" 1024", buffer, "%20.0d", 1024); SPRINTF_CHECK(" -1024", buffer, "%20.0d", -1024); SPRINTF_CHECK(" ", buffer, "%20.d", 0); @@ -972,6 +966,19 @@ SPRINTF_TEST_CASE(pointer) SPRINTF_TEST_CASE(string_length) { char buffer[base_buffer_size]; +#if !defined(RT_KLIBC_USING_LIBC_VSNPRINTF) + char unterminated[] = { 'A', 'B', 'C' }; +#endif + + SPRINTF_CHECK("", buffer, "%.0s", "Hello testing"); + SPRINTF_CHECK(" ", buffer, "%20.0s", "Hello testing"); + SPRINTF_CHECK("", buffer, "%.s", "Hello testing"); + SPRINTF_CHECK(" ", buffer, "%20.s", "Hello testing"); + SPRINTF_CHECK("", buffer, "%.*s", 0, "Hello testing"); +#if !defined(RT_KLIBC_USING_LIBC_VSNPRINTF) + SPRINTF_CHECK("Hello testing", buffer, "%.*s", -1, "Hello testing"); + SPRINTF_CHECK("ABC", buffer, "%.3s", unterminated); +#endif SPRINTF_CHECK("This", buffer, "%.4s", "This is a test"); SPRINTF_CHECK("test", buffer, "%.4s", "test"); SPRINTF_CHECK("123", buffer, "%.7s", "123"); @@ -989,14 +996,16 @@ SPRINTF_TEST_CASE(misc) { char buffer[base_buffer_size]; SPRINTF_CHECK("53000atest-20 bit", buffer, "%u%u%ctest%d %s", 5, 3000, 'a', -20, "bit"); -#ifdef RT_KLIBC_USING_VSNPRINTF_DECIMAL_SPECIFIERS - SPRINTF_CHECK("0.33", buffer, "%.*f", 2, 0.33333333); SPRINTF_CHECK("1", buffer, "%.*d", -1, 1); SPRINTF_CHECK("foo", buffer, "%.3s", "foobar"); SPRINTF_CHECK(" ", buffer, "% .0d", 0); + SPRINTF_CHECK("5", buffer, "%.0d", 5); + SPRINTF_CHECK("", buffer, "%.0d", 0); SPRINTF_CHECK(" 00004", buffer, "%10.5d", 4); SPRINTF_CHECK("hi x", buffer, "%*sx", -3, "hi"); SPRINTF_CHECK("00123 ", buffer, "%-20.5i", 123); +#ifdef RT_KLIBC_USING_VSNPRINTF_DECIMAL_SPECIFIERS + SPRINTF_CHECK("0.33", buffer, "%.*f", 2, 0.33333333); SPRINTF_CHECK("-67224.546875000000000000", buffer, "%.18f", -67224.546875); #endif /* RT_KLIBC_USING_VSNPRINTF_DECIMAL_SPECIFIERS */ #ifdef RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS