[libc-commits] [libc] f6b724f - [libc] Add basic fuzz target for the printf parser

Michael Jones via libc-commits libc-commits at lists.llvm.org
Fri Feb 17 11:18:47 PST 2023


Author: Michael Jones
Date: 2023-02-17T11:18:40-08:00
New Revision: f6b724f1f9c8d8019b8a425b6fb52e1cf6fc0215

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

LOG: [libc] Add basic fuzz target for the printf parser

The goal is to fuzz the entirety of printf, but the plan is to do it in
pieces for simplicity. This test fuzzes just the parser, while later
tests will fuzz the converters. This also adds a mock version of the
arg_list class.

Reviewed By: sivachandra

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

Added: 
    libc/fuzzing/stdio/CMakeLists.txt
    libc/fuzzing/stdio/printf_parser_fuzz.cpp

Modified: 
    libc/fuzzing/CMakeLists.txt
    libc/src/stdio/printf_core/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/libc/fuzzing/CMakeLists.txt b/libc/fuzzing/CMakeLists.txt
index 5d8a23352470e..a3ef888167ee3 100644
--- a/libc/fuzzing/CMakeLists.txt
+++ b/libc/fuzzing/CMakeLists.txt
@@ -3,4 +3,5 @@ add_custom_target(libc-fuzzer)
 
 add_subdirectory(math)
 add_subdirectory(stdlib)
+add_subdirectory(stdio)
 add_subdirectory(string)

diff  --git a/libc/fuzzing/stdio/CMakeLists.txt b/libc/fuzzing/stdio/CMakeLists.txt
new file mode 100644
index 0000000000000..fac982c5b6173
--- /dev/null
+++ b/libc/fuzzing/stdio/CMakeLists.txt
@@ -0,0 +1,9 @@
+add_libc_fuzzer(
+  printf_parser_fuzz
+  SRCS
+    printf_parser_fuzz.cpp
+  DEPENDS
+    libc.src.stdio.printf_core.mock_parser
+  COMPILE_OPTIONS
+    -DLIBC_COPT_MOCK_ARG_LIST
+)

diff  --git a/libc/fuzzing/stdio/printf_parser_fuzz.cpp b/libc/fuzzing/stdio/printf_parser_fuzz.cpp
new file mode 100644
index 0000000000000..05cd616ca48b0
--- /dev/null
+++ b/libc/fuzzing/stdio/printf_parser_fuzz.cpp
@@ -0,0 +1,73 @@
+//===-- printf_parser_fuzz.cpp --------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// Fuzzing test for llvm-libc qsort implementation.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LIBC_COPT_MOCK_ARG_LIST
+#error The printf Parser Fuzzer must be compiled with LIBC_COPT_MOCK_ARG_LIST, and the parser itself must also be compiled with that option when it's linked against the fuzzer.
+#endif
+
+#include "src/__support/arg_list.h"
+#include "src/stdio/printf_core/parser.h"
+
+#include <stdarg.h>
+#include <stdint.h>
+
+using namespace __llvm_libc;
+
+// The design for the printf parser fuzzer is fairly simple. The parser uses a
+// mock arg list that will never fail, and is passed a randomized string. The
+// format sections it outputs are checked against a count of the number of '%'
+// signs are in the original string. This is a fairly basic test, and the main
+// intent is to run this under sanitizers, which will check for buffer overruns.
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+  char *in_str = new char[size + 1];
+
+  for (size_t i = 0; i < size; ++i)
+    in_str[i] = data[i];
+
+  in_str[size] = '\0';
+
+  auto mock_arg_list = internal::MockArgList();
+
+  auto parser = printf_core::Parser(in_str, mock_arg_list);
+
+  int str_percent_count = 0;
+
+  for (size_t i = 0; i < size && in_str[i] != '\0'; ++i) {
+    if (in_str[i] == '%') {
+      ++str_percent_count;
+    }
+  }
+
+  int section_percent_count = 0;
+
+  for (printf_core::FormatSection cur_section = parser.get_next_section();
+       !cur_section.raw_string.empty();
+       cur_section = parser.get_next_section()) {
+    if (cur_section.has_conv) {
+      ++section_percent_count;
+      if (cur_section.conv_name == '%') {
+        ++section_percent_count;
+      }
+    } else if (cur_section.raw_string[0] == '%') {
+      // If the conversion would be undefined, it's instead raw, but it still
+      // starts with a %.
+      ++section_percent_count;
+    }
+  }
+
+  if (str_percent_count != section_percent_count) {
+    __builtin_trap();
+  }
+
+  delete[] in_str;
+  return 0;
+}

diff  --git a/libc/src/stdio/printf_core/CMakeLists.txt b/libc/src/stdio/printf_core/CMakeLists.txt
index c908b9198903b..b48feea28ec3b 100644
--- a/libc/src/stdio/printf_core/CMakeLists.txt
+++ b/libc/src/stdio/printf_core/CMakeLists.txt
@@ -25,6 +25,25 @@ add_object_library(
     libc.src.__support.common
 )
 
+add_object_library(
+  mock_parser
+  SRCS
+    parser.cpp
+  HDRS
+    parser.h
+  DEPENDS
+    .core_structs
+    libc.src.__support.arg_list
+    libc.src.__support.ctype_utils
+    libc.src.__support.str_to_integer
+    libc.src.__support.CPP.bit
+    libc.src.__support.CPP.string_view
+    libc.src.__support.CPP.type_traits
+    libc.src.__support.common
+  COMPILE_OPTIONS
+    -DLIBC_COPT_MOCK_ARG_LIST
+)
+
 add_object_library(
   string_writer
   SRCS


        


More information about the libc-commits mailing list