aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com>2023-04-21 01:11:35 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-04-21 01:11:35 +0000
commit55c70807a6adc8a06b32aa7821c5a01133809b51 (patch)
tree666d371eaec84540001bc3ee67ba088b57be00e2
parent8e205461382f8c5b695cbdf9783de212648f4207 (diff)
parent10f58945716aba62c0a881e74b18b6a2b0824298 (diff)
downloadbionic-55c70807a6adc8a06b32aa7821c5a01133809b51.tar.gz
Merge "Implement C23 printf 'w' length modifiers" am: 8ec9b81378 am: 87ca1746d9 am: 10f5894571
Original change: https://android-review.googlesource.com/c/platform/bionic/+/2532359 Change-Id: Ied6a2458fdf732c722fe7fa62c1a2435de688422 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--libc/stdio/printf_common.h11
-rw-r--r--libc/stdio/vfprintf.cpp28
-rw-r--r--libc/stdio/vfwprintf.cpp28
-rw-r--r--tests/stdio_test.cpp141
4 files changed, 208 insertions, 0 deletions
diff --git a/libc/stdio/printf_common.h b/libc/stdio/printf_common.h
index e7618354e..b0055f0ff 100644
--- a/libc/stdio/printf_common.h
+++ b/libc/stdio/printf_common.h
@@ -528,6 +528,17 @@ static int __find_arguments(const CHAR_TYPE* fmt0, va_list ap, union arg** argta
case 'b':
ADDUARG();
break;
+ case 'w':
+ n = 0;
+ ch = *fmt++;
+ while (is_digit(ch)) {
+ APPEND_DIGIT(n, ch);
+ ch = *fmt++;
+ }
+ if (n == 64) {
+ flags |= LLONGINT;
+ }
+ goto reswitch;
default: /* "%?" prints ?, unless ? is NUL */
if (ch == '\0') goto done;
break;
diff --git a/libc/stdio/vfprintf.cpp b/libc/stdio/vfprintf.cpp
index d83a5bf44..b7c68dd65 100644
--- a/libc/stdio/vfprintf.cpp
+++ b/libc/stdio/vfprintf.cpp
@@ -521,6 +521,34 @@ int FUNCTION_NAME(FILE* fp, const CHAR_TYPE* fmt0, va_list ap) {
_umax = UARG();
base = DEC;
goto nosign;
+ case 'w':
+ n = 0;
+ ch = *fmt++;
+ while (is_digit(ch)) {
+ APPEND_DIGIT(n, ch);
+ ch = *fmt++;
+ }
+ switch (n) {
+ case 8: {
+ flags |= CHARINT;
+ goto reswitch;
+ }
+ case 16: {
+ flags |= SHORTINT;
+ goto reswitch;
+ }
+ case 32: {
+ goto reswitch;
+ }
+ case 64: {
+ flags |= LLONGINT;
+ goto reswitch;
+ }
+ default: {
+ __fortify_fatal("%%w%d is unsupported", n);
+ break;
+ }
+ }
case 'X':
xdigs = xdigs_upper;
goto hex;
diff --git a/libc/stdio/vfwprintf.cpp b/libc/stdio/vfwprintf.cpp
index 9819a731c..52ae64b6e 100644
--- a/libc/stdio/vfwprintf.cpp
+++ b/libc/stdio/vfwprintf.cpp
@@ -510,6 +510,34 @@ int FUNCTION_NAME(FILE* fp, const CHAR_TYPE* fmt0, va_list ap) {
_umax = UARG();
base = DEC;
goto nosign;
+ case 'w':
+ n = 0;
+ ch = *fmt++;
+ while (is_digit(ch)) {
+ APPEND_DIGIT(n, ch);
+ ch = *fmt++;
+ }
+ switch (n) {
+ case 8: {
+ flags |= CHARINT;
+ goto reswitch;
+ }
+ case 16: {
+ flags |= SHORTINT;
+ goto reswitch;
+ }
+ case 32: {
+ goto reswitch;
+ }
+ case 64: {
+ flags |= LLONGINT;
+ goto reswitch;
+ }
+ default: {
+ __fortify_fatal("%%w%d is unsupported", n);
+ break;
+ }
+ }
case 'X':
xdigs = xdigs_upper;
goto hex;
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index 1275b45e6..0e267c516 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -3275,3 +3275,144 @@ TEST(STDIO_TEST, swscanf_b) {
EXPECT_EQ(0, i);
EXPECT_EQ('b', ch);
}
+
+TEST(STDIO_TEST, snprintf_w_base) {
+#if defined(__BIONIC__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wformat-invalid-specifier"
+#pragma clang diagnostic ignored "-Wconstant-conversion"
+ char buf[BUFSIZ];
+ int8_t a = 0b101;
+ snprintf(buf, sizeof(buf), "<%w8b>", a);
+ EXPECT_STREQ("<101>", buf);
+ int8_t b1 = 0xFF;
+ snprintf(buf, sizeof(buf), "<%w8d>", b1);
+ EXPECT_STREQ("<-1>", buf);
+ int8_t b2 = 0x1FF;
+ snprintf(buf, sizeof(buf), "<%w8d>", b2);
+ EXPECT_STREQ("<-1>", buf);
+ int16_t c = 0xFFFF;
+ snprintf(buf, sizeof(buf), "<%w16i>", c);
+ EXPECT_STREQ("<-1>", buf);
+ int32_t d = 021;
+ snprintf(buf, sizeof(buf), "<%w32o>", d);
+ EXPECT_STREQ("<21>", buf);
+ uint32_t e = -1;
+ snprintf(buf, sizeof(buf), "<%w32u>", e);
+ EXPECT_STREQ("<4294967295>", buf);
+ int64_t f = 0x3b;
+ snprintf(buf, sizeof(buf), "<%w64x>", f);
+ EXPECT_STREQ("<3b>", buf);
+ snprintf(buf, sizeof(buf), "<%w64X>", f);
+ EXPECT_STREQ("<3B>", buf);
+#pragma clang diagnostic pop
+#else
+ GTEST_SKIP() << "no %w in glibc";
+#endif
+}
+
+TEST(STDIO_TEST, snprintf_w_arguments_reordering) {
+#if defined(__BIONIC__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wformat-invalid-specifier"
+#pragma clang diagnostic ignored "-Wformat-extra-args"
+ char buf[BUFSIZ];
+ int32_t a = 0xaaaaaaaa;
+ int64_t b = 0x11111111'22222222;
+ int64_t c = 0x33333333'44444444;
+ int64_t d = 0xaaaaaaaa'aaaaaaaa;
+ snprintf(buf, sizeof(buf), "<%2$w32b --- %1$w64x>", c, a);
+ EXPECT_STREQ("<10101010101010101010101010101010 --- 3333333344444444>", buf);
+ snprintf(buf, sizeof(buf), "<%3$w64b --- %1$w64x --- %2$w64x>", b, c, d);
+ EXPECT_STREQ(
+ "<1010101010101010101010101010101010101010101010101010101010101010 --- 1111111122222222 --- "
+ "3333333344444444>",
+ buf);
+#pragma clang diagnostic pop
+#else
+ GTEST_SKIP() << "no %w in glibc";
+#endif
+}
+
+TEST(STDIO_TEST, snprintf_invalid_w_width) {
+#if defined(__BIONIC__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wformat-invalid-specifier"
+ char buf[BUFSIZ];
+ int32_t a = 100;
+ EXPECT_DEATH(snprintf(buf, sizeof(buf), "%w20d", &a), "%w20 is unsupported");
+#pragma clang diagnostic pop
+#else
+ GTEST_SKIP() << "no %w in glibc";
+#endif
+}
+
+TEST(STDIO_TEST, swprintf_w_base) {
+#if defined(__BIONIC__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wformat-invalid-specifier"
+#pragma clang diagnostic ignored "-Wconstant-conversion"
+ wchar_t buf[BUFSIZ];
+ int8_t a = 0b101;
+ swprintf(buf, sizeof(buf), L"<%w8b>", a);
+ EXPECT_EQ(std::wstring(L"<101>"), buf);
+ int8_t b1 = 0xFF;
+ swprintf(buf, sizeof(buf), L"<%w8d>", b1);
+ EXPECT_EQ(std::wstring(L"<-1>"), buf);
+ int8_t b2 = 0x1FF;
+ swprintf(buf, sizeof(buf), L"<%w8d>", b2);
+ EXPECT_EQ(std::wstring(L"<-1>"), buf);
+ int16_t c = 0xFFFF;
+ swprintf(buf, sizeof(buf), L"<%w16i>", c);
+ EXPECT_EQ(std::wstring(L"<-1>"), buf);
+ int32_t d = 021;
+ swprintf(buf, sizeof(buf), L"<%w32o>", d);
+ EXPECT_EQ(std::wstring(L"<21>"), buf);
+ uint32_t e = -1;
+ swprintf(buf, sizeof(buf), L"<%w32u>", e);
+ EXPECT_EQ(std::wstring(L"<4294967295>"), buf);
+ int64_t f = 0x3b;
+ swprintf(buf, sizeof(buf), L"<%w64x>", f);
+ EXPECT_EQ(std::wstring(L"<3b>"), buf);
+ swprintf(buf, sizeof(buf), L"<%w64X>", f);
+ EXPECT_EQ(std::wstring(L"<3B>"), buf);
+#pragma clang diagnostic pop
+#else
+ GTEST_SKIP() << "no %w in glibc";
+#endif
+}
+
+TEST(STDIO_TEST, swprintf_w_arguments_reordering) {
+#if defined(__BIONIC__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wformat-invalid-specifier"
+#pragma clang diagnostic ignored "-Wformat-extra-args"
+ wchar_t buf[BUFSIZ];
+ int32_t a = 0xaaaaaaaa;
+ int64_t b = 0x11111111'22222222;
+ int64_t c = 0x33333333'44444444;
+ int64_t d = 0xaaaaaaaa'aaaaaaaa;
+ swprintf(buf, sizeof(buf), L"<%2$w32b --- %1$w64x>", c, a);
+ EXPECT_EQ(std::wstring(L"<10101010101010101010101010101010 --- 3333333344444444>"), buf);
+ swprintf(buf, sizeof(buf), L"<%3$w64b --- %1$w64x --- %2$w64x>", b, c, d);
+ EXPECT_EQ(std::wstring(L"<1010101010101010101010101010101010101010101010101010101010101010 --- "
+ L"1111111122222222 --- 3333333344444444>"),
+ buf);
+#pragma clang diagnostic pop
+#else
+ GTEST_SKIP() << "no %w in glibc";
+#endif
+}
+
+TEST(STDIO_TEST, swprintf_invalid_w_width) {
+#if defined(__BIONIC__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wformat-invalid-specifier"
+ wchar_t buf[BUFSIZ];
+ int32_t a = 100;
+ EXPECT_DEATH(swprintf(buf, sizeof(buf), L"%w20d", &a), "%w20 is unsupported");
+#pragma clang diagnostic pop
+#else
+ GTEST_SKIP() << "no %w in glibc";
+#endif
+} \ No newline at end of file