[libc-commits] [libc] [libc] Fix incorrect printing for alt mode ints (PR #70252)

via libc-commits libc-commits at lists.llvm.org
Wed Oct 25 13:46:54 PDT 2023


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libc

Author: None (michaelrj-google)

<details>
<summary>Changes</summary>

Previously, our printf would incorrectly handle conversions like
("%#x",0) and ("%#o",0). This patch corrects the behavior to match what
is described in the standard.


---
Full diff: https://github.com/llvm/llvm-project/pull/70252.diff


2 Files Affected:

- (modified) libc/src/stdio/printf_core/int_converter.h (+14-2) 
- (modified) libc/test/src/stdio/sprintf_test.cpp (+16) 


``````````diff
diff --git a/libc/src/stdio/printf_core/int_converter.h b/libc/src/stdio/printf_core/int_converter.h
index 348e81a1fa536bf..13fcf3f1aa2edac 100644
--- a/libc/src/stdio/printf_core/int_converter.h
+++ b/libc/src/stdio/printf_core/int_converter.h
@@ -113,7 +113,7 @@ LIBC_INLINE int convert_int(Writer *writer, const FormatSection &to_conv) {
   size_t prefix_len;
   char prefix[2];
   if ((to_lower(to_conv.conv_name) == 'x') &&
-      ((flags & FormatFlags::ALTERNATE_FORM) != 0)) {
+      ((flags & FormatFlags::ALTERNATE_FORM) != 0) && num != 0) {
     prefix_len = 2;
     prefix[0] = '0';
     prefix[1] = a + ('x' - 'a');
@@ -158,8 +158,20 @@ LIBC_INLINE int convert_int(Writer *writer, const FormatSection &to_conv) {
                               prefix_len);
   }
 
+  // The standard says that alternate form for the o conversion "increases
+  // the precision, if and only if necessary, to force the first digit of the
+  // result to be a zero (if the value and precision are both 0, a single 0 is
+  // printed)"
+  // This if checks the following conditions:
+  // 1) is this an o conversion in alternate form?
+  // 2) does this number has a leading zero?
+  //    2a) ... because there are additional leading zeroes?
+  //    2b) ... because it is just "0", unless it will not write any digits.
+  const bool has_leading_zero =
+      (zeroes > 0) || ((num == 0) && (digits_written != 0));
   if ((to_conv.conv_name == 'o') &&
-      ((to_conv.flags & FormatFlags::ALTERNATE_FORM) != 0) && zeroes < 1) {
+      ((to_conv.flags & FormatFlags::ALTERNATE_FORM) != 0) &&
+      !has_leading_zero) {
     zeroes = 1;
     --spaces;
   }
diff --git a/libc/test/src/stdio/sprintf_test.cpp b/libc/test/src/stdio/sprintf_test.cpp
index a68ee97d6d6edc4..b2c321c0b15c9dc 100644
--- a/libc/test/src/stdio/sprintf_test.cpp
+++ b/libc/test/src/stdio/sprintf_test.cpp
@@ -329,6 +329,10 @@ TEST(LlvmLibcSPrintfTest, HexConv) {
   EXPECT_EQ(written, 5);
   ASSERT_STREQ(buff, "0xd3f");
 
+  written = LIBC_NAMESPACE::sprintf(buff, "%#x", 0);
+  EXPECT_EQ(written, 1);
+  ASSERT_STREQ(buff, "0");
+
   written = LIBC_NAMESPACE::sprintf(buff, "%#X", 0xE40);
   EXPECT_EQ(written, 5);
   ASSERT_STREQ(buff, "0XE40");
@@ -359,6 +363,10 @@ TEST(LlvmLibcSPrintfTest, HexConv) {
   EXPECT_EQ(written, 9);
   ASSERT_STREQ(buff, "  0X009D4");
 
+  written = LIBC_NAMESPACE::sprintf(buff, "%#.x", 0);
+  EXPECT_EQ(written, 0);
+  ASSERT_STREQ(buff, "");
+
   written = LIBC_NAMESPACE::sprintf(buff, "%-7.5x", 0x260);
   EXPECT_EQ(written, 7);
   ASSERT_STREQ(buff, "00260  ");
@@ -516,6 +524,10 @@ TEST(LlvmLibcSPrintfTest, OctConv) {
   EXPECT_EQ(written, 4);
   ASSERT_STREQ(buff, "0234");
 
+  written = LIBC_NAMESPACE::sprintf(buff, "%#o", 0);
+  EXPECT_EQ(written, 1);
+  ASSERT_STREQ(buff, "0");
+
   written = LIBC_NAMESPACE::sprintf(buff, "%05o", 0470);
   EXPECT_EQ(written, 5);
   ASSERT_STREQ(buff, "00470");
@@ -534,6 +546,10 @@ TEST(LlvmLibcSPrintfTest, OctConv) {
   EXPECT_EQ(written, 7);
   ASSERT_STREQ(buff, "0703   ");
 
+  written = LIBC_NAMESPACE::sprintf(buff, "%#.o", 0);
+  EXPECT_EQ(written, 1);
+  ASSERT_STREQ(buff, "0");
+
   written = LIBC_NAMESPACE::sprintf(buff, "%7.5o", 0314);
   EXPECT_EQ(written, 7);
   ASSERT_STREQ(buff, "  00314");

``````````

</details>


https://github.com/llvm/llvm-project/pull/70252


More information about the libc-commits mailing list