Skip to content

Commit dd51ae8

Browse files
[libc] Fix printf %p format
The %p format wasn't correctly passing along flags and modifiers to the integer conversion behind the scenes. This patch fixes that behavior, as well as changing the nullptr behavior to be a string conversion behind the scenes. Reviewed By: lntue, jhuber6 Differential Revision: https://reviews.llvm.org/D159458
1 parent 6678f60 commit dd51ae8

File tree

2 files changed

+60
-10
lines changed

2 files changed

+60
-10
lines changed

libc/src/stdio/printf_core/ptr_converter.h

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,27 @@
1414
#include "src/stdio/printf_core/converter_utils.h"
1515
#include "src/stdio/printf_core/core_structs.h"
1616
#include "src/stdio/printf_core/int_converter.h"
17+
#include "src/stdio/printf_core/string_converter.h"
1718
#include "src/stdio/printf_core/writer.h"
1819

1920
namespace __llvm_libc {
2021
namespace printf_core {
2122

2223
LIBC_INLINE int convert_pointer(Writer *writer, const FormatSection &to_conv) {
23-
if (to_conv.conv_val_ptr == (void *)(nullptr)) {
24-
RET_IF_RESULT_NEGATIVE(writer->write("(nullptr)"));
25-
} else {
26-
FormatSection hex_conv;
27-
hex_conv.has_conv = true;
28-
hex_conv.conv_name = 'x';
29-
hex_conv.flags = FormatFlags::ALTERNATE_FORM;
30-
hex_conv.conv_val_raw = reinterpret_cast<uintptr_t>(to_conv.conv_val_ptr);
31-
return convert_int(writer, hex_conv);
24+
FormatSection new_conv = to_conv;
25+
26+
if (to_conv.conv_val_ptr == nullptr) {
27+
constexpr char NULLPTR_STR[] = "(nullptr)";
28+
new_conv.conv_name = 's';
29+
new_conv.conv_val_ptr = const_cast<char *>(NULLPTR_STR);
30+
return convert_string(writer, new_conv);
3231
}
33-
return WRITE_OK;
32+
new_conv.conv_name = 'x';
33+
new_conv.flags =
34+
static_cast<FormatFlags>(to_conv.flags | FormatFlags::ALTERNATE_FORM);
35+
new_conv.length_modifier = LengthModifier::t;
36+
new_conv.conv_val_raw = reinterpret_cast<uintptr_t>(to_conv.conv_val_ptr);
37+
return convert_int(writer, new_conv);
3438
}
3539

3640
} // namespace printf_core

libc/test/src/stdio/sprintf_test.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,8 +394,54 @@ TEST(LlvmLibcSPrintfTest, PointerConv) {
394394
EXPECT_EQ(written, 10);
395395
ASSERT_STREQ(buff, "0x1a2b3c4d");
396396

397+
if constexpr (sizeof(void *) > 4) {
398+
written = __llvm_libc::sprintf(buff, "%p", 0x1a2b3c4d5e6f7081);
399+
EXPECT_EQ(written, 18);
400+
ASSERT_STREQ(buff, "0x1a2b3c4d5e6f7081");
401+
}
402+
397403
written = __llvm_libc::sprintf(buff, "%p", buff);
398404
EXPECT_GT(written, 0);
405+
406+
// Width tests:
407+
408+
written = __llvm_libc::sprintf(buff, "%20p", nullptr);
409+
EXPECT_EQ(written, 20);
410+
ASSERT_STREQ(buff, " (nullptr)");
411+
412+
written = __llvm_libc::sprintf(buff, "%20p", 0x1a2b3c4d);
413+
EXPECT_EQ(written, 20);
414+
ASSERT_STREQ(buff, " 0x1a2b3c4d");
415+
416+
// Flag tests:
417+
418+
written = __llvm_libc::sprintf(buff, "%-20p", nullptr);
419+
EXPECT_EQ(written, 20);
420+
ASSERT_STREQ(buff, "(nullptr) ");
421+
422+
written = __llvm_libc::sprintf(buff, "%-20p", 0x1a2b3c4d);
423+
EXPECT_EQ(written, 20);
424+
ASSERT_STREQ(buff, "0x1a2b3c4d ");
425+
426+
// Using the 0 flag is technically undefined, but here we're following the
427+
// convention of matching the behavior of %#x.
428+
written = __llvm_libc::sprintf(buff, "%020p", 0x1a2b3c4d);
429+
EXPECT_EQ(written, 20);
430+
ASSERT_STREQ(buff, "0x00000000001a2b3c4d");
431+
432+
// Precision tests:
433+
// These are all undefined behavior. The precision option is undefined for %p.
434+
435+
// Precision specifies the number of characters for a string conversion.
436+
written = __llvm_libc::sprintf(buff, "%.5p", nullptr);
437+
EXPECT_EQ(written, 5);
438+
ASSERT_STREQ(buff, "(null");
439+
440+
// Precision specifies the number of digits to be written for %x conversions,
441+
// and the "0x" doesn't count as part of the digits.
442+
written = __llvm_libc::sprintf(buff, "%.20p", 0x1a2b3c4d);
443+
EXPECT_EQ(written, 22);
444+
ASSERT_STREQ(buff, "0x0000000000001a2b3c4d");
399445
}
400446

401447
TEST(LlvmLibcSPrintfTest, OctConv) {

0 commit comments

Comments
 (0)