diff --git a/libc/async_safe/async_safe_log.cpp b/libc/async_safe/async_safe_log.cpp index 8b2a32b14..2380e686d 100644 --- a/libc/async_safe/async_safe_log.cpp +++ b/libc/async_safe/async_safe_log.cpp @@ -251,6 +251,7 @@ static void out_vformat(Out& o, const char* format, va_list args) { char sign = '\0'; int width = -1; int prec = -1; + bool alternate = false; size_t bytelen = sizeof(int); int slen; char buffer[32]; /* temporary buffer used to format numbers */ @@ -293,6 +294,9 @@ static void out_vformat(Out& o, const char* format, va_list args) { } else if (c == ' ' || c == '+') { sign = c; continue; + } else if (c == '#') { + alternate = true; + continue; } break; } @@ -344,9 +348,6 @@ static void out_vformat(Out& o, const char* format, va_list args) { if (c == 's') { /* string */ str = va_arg(args, const char*); - if (str == nullptr) { - str = "(null)"; - } } else if (c == 'c') { /* character */ /* NOTE: char is promoted to int when passed through the stack */ @@ -357,6 +358,9 @@ static void out_vformat(Out& o, const char* format, va_list args) { buffer[0] = '0'; buffer[1] = 'x'; format_integer(buffer + 2, sizeof(buffer) - 2, value, 'x'); + } else if (c == 'm') { + char buf[256]; + str = strerror_r(errno, buf, sizeof(buf)); } else if (c == 'd' || c == 'i' || c == 'o' || c == 'u' || c == 'x' || c == 'X') { /* integers - first read value from stack */ uint64_t value; @@ -388,8 +392,19 @@ static void out_vformat(Out& o, const char* format, va_list args) { value = static_cast((static_cast(value << shift)) >> shift); } - /* format the number properly into our buffer */ - format_integer(buffer, sizeof(buffer), value, c); + if (alternate && value != 0 && (c == 'x' || c == 'o')) { + if (c == 'x') { + buffer[0] = '0'; + buffer[1] = 'x'; + format_integer(buffer + 2, sizeof(buffer) - 2, value, c); + } else { + buffer[0] = '0'; + format_integer(buffer + 1, sizeof(buffer) - 1, value, c); + } + } else { + /* format the number properly into our buffer */ + format_integer(buffer, sizeof(buffer), value, c); + } } else if (c == '%') { buffer[0] = '%'; buffer[1] = '\0'; @@ -397,6 +412,10 @@ static void out_vformat(Out& o, const char* format, va_list args) { __assert(__FILE__, __LINE__, "conversion specifier unsupported"); } + if (str == nullptr) { + str = "(null)"; + } + /* if we are here, 'str' points to the content that must be * outputted. handle padding and alignment now */ diff --git a/tests/async_safe_test.cpp b/tests/async_safe_test.cpp index 6c4758e71..f52387e97 100644 --- a/tests/async_safe_test.cpp +++ b/tests/async_safe_test.cpp @@ -64,6 +64,10 @@ TEST(async_safe_log, smoke) { async_safe_format_buffer(buf, sizeof(buf), "a%ldb", 70000L); EXPECT_STREQ("a70000b", buf); + errno = EINVAL; + async_safe_format_buffer(buf, sizeof(buf), "a%mZ"); + EXPECT_STREQ("aInvalid argumentZ", buf); + async_safe_format_buffer(buf, sizeof(buf), "a%pb", reinterpret_cast(0xb0001234)); EXPECT_STREQ("a0xb0001234b", buf); @@ -97,6 +101,30 @@ TEST(async_safe_log, smoke) { async_safe_format_buffer(buf, sizeof(buf), "a%03d:%d:%02dz", 5, 5, 5); EXPECT_STREQ("a005:5:05z", buf); + async_safe_format_buffer(buf, sizeof(buf), "a%#xZ", 34); + EXPECT_STREQ("a0x22Z", buf); + + async_safe_format_buffer(buf, sizeof(buf), "a%#xZ", 0); + EXPECT_STREQ("a0Z", buf); + + async_safe_format_buffer(buf, sizeof(buf), "a%#5xZ", 20); + EXPECT_STREQ("a 0x14Z", buf); + + snprintf(buf, sizeof(buf), "a%#08.8xZ", 1); + EXPECT_STREQ("a0x00000001Z", buf); + + async_safe_format_buffer(buf, sizeof(buf), "a%#oZ", 777); + EXPECT_STREQ("a01411Z", buf); + + async_safe_format_buffer(buf, sizeof(buf), "a%#oZ", 0); + EXPECT_STREQ("a0Z", buf); + + async_safe_format_buffer(buf, sizeof(buf), "a%#6oZ", 15); + EXPECT_STREQ("a 017Z", buf); + + snprintf(buf, sizeof(buf), "a%#08.8oZ", 11); + EXPECT_STREQ("a00000013Z", buf); + void* p = nullptr; async_safe_format_buffer(buf, sizeof(buf), "a%d,%pz", 5, p); EXPECT_STREQ("a5,0x0z", buf);