[libc] Add basic fuzz target for the printf parser
authorMichael Jones <michaelrj@google.com>
Fri, 10 Feb 2023 23:00:32 +0000 (15:00 -0800)
committerMichael Jones <michaelrj@google.com>
Fri, 17 Feb 2023 19:18:40 +0000 (11:18 -0800)
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

libc/fuzzing/CMakeLists.txt
libc/fuzzing/stdio/CMakeLists.txt [new file with mode: 0644]
libc/fuzzing/stdio/printf_parser_fuzz.cpp [new file with mode: 0644]
libc/src/stdio/printf_core/CMakeLists.txt

index 5d8a233..a3ef888 100644 (file)
@@ -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 (file)
index 0000000..fac982c
--- /dev/null
@@ -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 (file)
index 0000000..05cd616
--- /dev/null
@@ -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;
+}
index c908b91..b48feea 100644 (file)
@@ -26,6 +26,25 @@ add_object_library(
 )
 
 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
     string_writer.cpp