Skip to content

Commit 6e863c4

Browse files
[libc] Fix incorrect printing for alt mode ints (#70252)
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.
1 parent 793e636 commit 6e863c4

File tree

2 files changed

+30
-2
lines changed

2 files changed

+30
-2
lines changed

libc/src/stdio/printf_core/int_converter.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ LIBC_INLINE int convert_int(Writer *writer, const FormatSection &to_conv) {
113113
size_t prefix_len;
114114
char prefix[2];
115115
if ((to_lower(to_conv.conv_name) == 'x') &&
116-
((flags & FormatFlags::ALTERNATE_FORM) != 0)) {
116+
((flags & FormatFlags::ALTERNATE_FORM) != 0) && num != 0) {
117117
prefix_len = 2;
118118
prefix[0] = '0';
119119
prefix[1] = a + ('x' - 'a');
@@ -158,8 +158,20 @@ LIBC_INLINE int convert_int(Writer *writer, const FormatSection &to_conv) {
158158
prefix_len);
159159
}
160160

161+
// The standard says that alternate form for the o conversion "increases
162+
// the precision, if and only if necessary, to force the first digit of the
163+
// result to be a zero (if the value and precision are both 0, a single 0 is
164+
// printed)"
165+
// This if checks the following conditions:
166+
// 1) is this an o conversion in alternate form?
167+
// 2) does this number has a leading zero?
168+
// 2a) ... because there are additional leading zeroes?
169+
// 2b) ... because it is just "0", unless it will not write any digits.
170+
const bool has_leading_zero =
171+
(zeroes > 0) || ((num == 0) && (digits_written != 0));
161172
if ((to_conv.conv_name == 'o') &&
162-
((to_conv.flags & FormatFlags::ALTERNATE_FORM) != 0) && zeroes < 1) {
173+
((to_conv.flags & FormatFlags::ALTERNATE_FORM) != 0) &&
174+
!has_leading_zero) {
163175
zeroes = 1;
164176
--spaces;
165177
}

libc/test/src/stdio/sprintf_test.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,10 @@ TEST(LlvmLibcSPrintfTest, HexConv) {
329329
EXPECT_EQ(written, 5);
330330
ASSERT_STREQ(buff, "0xd3f");
331331

332+
written = LIBC_NAMESPACE::sprintf(buff, "%#x", 0);
333+
EXPECT_EQ(written, 1);
334+
ASSERT_STREQ(buff, "0");
335+
332336
written = LIBC_NAMESPACE::sprintf(buff, "%#X", 0xE40);
333337
EXPECT_EQ(written, 5);
334338
ASSERT_STREQ(buff, "0XE40");
@@ -359,6 +363,10 @@ TEST(LlvmLibcSPrintfTest, HexConv) {
359363
EXPECT_EQ(written, 9);
360364
ASSERT_STREQ(buff, " 0X009D4");
361365

366+
written = LIBC_NAMESPACE::sprintf(buff, "%#.x", 0);
367+
EXPECT_EQ(written, 0);
368+
ASSERT_STREQ(buff, "");
369+
362370
written = LIBC_NAMESPACE::sprintf(buff, "%-7.5x", 0x260);
363371
EXPECT_EQ(written, 7);
364372
ASSERT_STREQ(buff, "00260 ");
@@ -516,6 +524,10 @@ TEST(LlvmLibcSPrintfTest, OctConv) {
516524
EXPECT_EQ(written, 4);
517525
ASSERT_STREQ(buff, "0234");
518526

527+
written = LIBC_NAMESPACE::sprintf(buff, "%#o", 0);
528+
EXPECT_EQ(written, 1);
529+
ASSERT_STREQ(buff, "0");
530+
519531
written = LIBC_NAMESPACE::sprintf(buff, "%05o", 0470);
520532
EXPECT_EQ(written, 5);
521533
ASSERT_STREQ(buff, "00470");
@@ -534,6 +546,10 @@ TEST(LlvmLibcSPrintfTest, OctConv) {
534546
EXPECT_EQ(written, 7);
535547
ASSERT_STREQ(buff, "0703 ");
536548

549+
written = LIBC_NAMESPACE::sprintf(buff, "%#.o", 0);
550+
EXPECT_EQ(written, 1);
551+
ASSERT_STREQ(buff, "0");
552+
537553
written = LIBC_NAMESPACE::sprintf(buff, "%7.5o", 0314);
538554
EXPECT_EQ(written, 7);
539555
ASSERT_STREQ(buff, " 00314");

0 commit comments

Comments
 (0)