[libc-commits] [libc] 88b8013 - [libc] add integer writing to printf

Michael Jones via libc-commits libc-commits at lists.llvm.org
Tue Jun 28 14:00:54 PDT 2022


Author: Michael Jones
Date: 2022-06-28T14:00:46-07:00
New Revision: 88b801392c9378abf26c4bb0eb3bd6a3bacdada7

URL: https://github.com/llvm/llvm-project/commit/88b801392c9378abf26c4bb0eb3bd6a3bacdada7
DIFF: https://github.com/llvm/llvm-project/commit/88b801392c9378abf26c4bb0eb3bd6a3bacdada7.diff

LOG: [libc] add integer writing to printf

This patch adds %n to printf, as well as a compiler flag to disable it.
This is due to it having serious security issues when misused.

Reviewed By: lntue

Differential Revision: https://reviews.llvm.org/D127517

Added: 
    libc/src/stdio/printf_core/write_int_converter.h

Modified: 
    libc/src/stdio/printf_core/CMakeLists.txt
    libc/src/stdio/printf_core/converter.cpp
    libc/src/stdio/printf_core/converter_atlas.h
    libc/src/stdio/printf_core/parser.cpp
    libc/test/src/stdio/sprintf_test.cpp

Removed: 
    


################################################################################
diff  --git a/libc/src/stdio/printf_core/CMakeLists.txt b/libc/src/stdio/printf_core/CMakeLists.txt
index 345ecc7e2eab8..b30a69f7a9573 100644
--- a/libc/src/stdio/printf_core/CMakeLists.txt
+++ b/libc/src/stdio/printf_core/CMakeLists.txt
@@ -64,6 +64,7 @@ add_object_library(
     hex_converter.h
     ptr_converter.h
     oct_converter.h
+    write_int_converter.h
   DEPENDS
     .writer
     .core_structs

diff  --git a/libc/src/stdio/printf_core/converter.cpp b/libc/src/stdio/printf_core/converter.cpp
index f809408ad0777..074b34568b12f 100644
--- a/libc/src/stdio/printf_core/converter.cpp
+++ b/libc/src/stdio/printf_core/converter.cpp
@@ -57,9 +57,10 @@ int convert(Writer *writer, const FormatSection &to_conv) {
   case 'g':
   case 'G':
     // return convert_float_mixed(writer, to_conv);
-  // TODO(michaelrj): add a flag to disable writing an int here
+#ifndef LLVM_LIBC_PRINTF_DISABLE_WRITE_INT
   case 'n':
-    // return convert_write_int(writer, to_conv);
+    return convert_write_int(writer, to_conv);
+#endif // LLVM_LIBC_PRINTF_DISABLE_WRITE_INT
   case 'p':
     return convert_pointer(writer, to_conv);
   default:

diff  --git a/libc/src/stdio/printf_core/converter_atlas.h b/libc/src/stdio/printf_core/converter_atlas.h
index 2c39255cdefe7..71354cc0b96ce 100644
--- a/libc/src/stdio/printf_core/converter_atlas.h
+++ b/libc/src/stdio/printf_core/converter_atlas.h
@@ -33,8 +33,9 @@
 // defines convert_float_hex_exp
 // defines convert_float_mixed
 
-// TODO(michaelrj): add a flag to disable writing an int here
-// defines convert_write_int
+#ifndef LLVM_LIBC_PRINTF_DISABLE_WRITE_INT
+#include "src/stdio/printf_core/write_int_converter.h"
+#endif // LLVM_LIBC_PRINTF_DISABLE_WRITE_INT
 
 // defines convert_pointer
 #include "src/stdio/printf_core/ptr_converter.h"

diff  --git a/libc/src/stdio/printf_core/parser.cpp b/libc/src/stdio/printf_core/parser.cpp
index c1f8ea90624b5..565e6a61b05ae 100644
--- a/libc/src/stdio/printf_core/parser.cpp
+++ b/libc/src/stdio/printf_core/parser.cpp
@@ -137,7 +137,9 @@ FormatSection Parser::get_next_section() {
         section.conv_val_raw = bit_cast<fputil::FPBits<long double>::UIntType>(
             GET_ARG_VAL_SIMPLEST(long double, conv_index));
       break;
+#ifndef LLVM_LIBC_PRINTF_DISABLE_WRITE_INT
     case ('n'):
+#endif // LLVM_LIBC_PRINTF_DISABLE_WRITE_INT
     case ('p'):
     case ('s'):
       section.conv_val_ptr = GET_ARG_VAL_SIMPLEST(void *, conv_index);
@@ -351,7 +353,9 @@ Parser::TypeDesc Parser::get_type_desc(size_t index) {
         else
           conv_size = TYPE_DESC<long double>;
         break;
+#ifndef LLVM_LIBC_PRINTF_DISABLE_WRITE_INT
       case ('n'):
+#endif // LLVM_LIBC_PRINTF_DISABLE_WRITE_INT
       case ('p'):
       case ('s'):
         conv_size = TYPE_DESC<void *>;

diff  --git a/libc/src/stdio/printf_core/write_int_converter.h b/libc/src/stdio/printf_core/write_int_converter.h
new file mode 100644
index 0000000000000..e8ed9496aa978
--- /dev/null
+++ b/libc/src/stdio/printf_core/write_int_converter.h
@@ -0,0 +1,65 @@
+//===-- Write integer Converter for printf ----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_WRITE_INT_CONVERTER_H
+#define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_WRITE_INT_CONVERTER_H
+
+#include "src/__support/CPP/Limits.h"
+#include "src/stdio/printf_core/core_structs.h"
+#include "src/stdio/printf_core/writer.h"
+
+#include <inttypes.h>
+#include <stddef.h>
+
+namespace __llvm_libc {
+namespace printf_core {
+
+int inline convert_write_int(Writer *writer, const FormatSection &to_conv) {
+
+  // This is an additional check added by LLVM-libc. The reason it returns -3 is
+  // because printf uses negative return values for errors, and -1 and -2 are
+  // already in use by the file_writer class for file errors.
+  if (to_conv.conv_val_ptr == nullptr)
+    return -3;
+
+  int written = writer->get_chars_written();
+
+  switch (to_conv.length_modifier) {
+  case LengthModifier::none:
+    *reinterpret_cast<int *>(to_conv.conv_val_ptr) = written;
+    break;
+  case LengthModifier::l:
+    *reinterpret_cast<long *>(to_conv.conv_val_ptr) = written;
+    break;
+  case LengthModifier::ll:
+  case LengthModifier::L:
+    *reinterpret_cast<long long *>(to_conv.conv_val_ptr) = written;
+    break;
+  case LengthModifier::h:
+    *reinterpret_cast<short *>(to_conv.conv_val_ptr) = written;
+    break;
+  case LengthModifier::hh:
+    *reinterpret_cast<signed char *>(to_conv.conv_val_ptr) = written;
+    break;
+  case LengthModifier::z:
+    *reinterpret_cast<size_t *>(to_conv.conv_val_ptr) = written;
+    break;
+  case LengthModifier::t:
+    *reinterpret_cast<ptr
diff _t *>(to_conv.conv_val_ptr) = written;
+    break;
+  case LengthModifier::j:
+    *reinterpret_cast<uintmax_t *>(to_conv.conv_val_ptr) = written;
+    break;
+  }
+  return 0;
+}
+
+} // namespace printf_core
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STDIO_PRINTF_CORE_WRITE_INT_CONVERTER_H

diff  --git a/libc/test/src/stdio/sprintf_test.cpp b/libc/test/src/stdio/sprintf_test.cpp
index 4c8e24e95329b..c274773c9c0ac 100644
--- a/libc/test/src/stdio/sprintf_test.cpp
+++ b/libc/test/src/stdio/sprintf_test.cpp
@@ -92,7 +92,7 @@ TEST(LlvmLibcSPrintfTest, IntConv) {
 
   // Length Modifier Tests.
 
-  written = __llvm_libc::sprintf(buff, "%hhu", 257); // 0x10001
+  written = __llvm_libc::sprintf(buff, "%hhu", 257); // 0x101
   EXPECT_EQ(written, 1);
   ASSERT_STREQ(buff, "1");
 
@@ -483,6 +483,41 @@ TEST(LlvmLibcSPrintfTest, OctConv) {
   ASSERT_STREQ(buff, "0077 01000000000000 002   ");
 }
 
+#ifndef LLVM_LIBC_PRINTF_DISABLE_WRITE_INT
+TEST(LlvmLibcSPrintfTest, WriteIntConv) {
+  char buff[64];
+  int written;
+  int test_val = -1;
+
+  test_val = -1;
+  written = __llvm_libc::sprintf(buff, "12345%n67890", &test_val);
+  EXPECT_EQ(written, 10);
+  EXPECT_EQ(test_val, 5);
+  ASSERT_STREQ(buff, "1234567890");
+
+  test_val = -1;
+  written = __llvm_libc::sprintf(buff, "%n", &test_val);
+  EXPECT_EQ(written, 0);
+  EXPECT_EQ(test_val, 0);
+  ASSERT_STREQ(buff, "");
+
+  test_val = 0x100;
+  written = __llvm_libc::sprintf(buff, "ABC%hhnDEF", &test_val);
+  EXPECT_EQ(written, 6);
+  EXPECT_EQ(test_val, 0x103);
+  ASSERT_STREQ(buff, "ABCDEF");
+
+  test_val = -1;
+  written = __llvm_libc::sprintf(buff, "%s%n", "87654321", &test_val);
+  EXPECT_EQ(written, 8);
+  EXPECT_EQ(test_val, 8);
+  ASSERT_STREQ(buff, "87654321");
+
+  written = __llvm_libc::sprintf(buff, "abc123%n", nullptr);
+  EXPECT_LT(written, 0);
+}
+#endif // LLVM_LIBC_PRINTF_DISABLE_WRITE_INT
+
 #ifndef LLVM_LIBC_PRINTF_DISABLE_INDEX_MODE
 TEST(LlvmLibcSPrintfTest, IndexModeParsing) {
   char buff[64];


        


More information about the libc-commits mailing list