1 | //===-- printf_parser_fuzz.cpp --------------------------------------------===// |
---|---|
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | /// |
9 | /// Fuzzing test for llvm-libc qsort implementation. |
10 | /// |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "src/__support/arg_list.h" |
14 | #include "src/stdio/printf_core/parser.h" |
15 | |
16 | #include <stdarg.h> |
17 | #include <stdint.h> |
18 | |
19 | using namespace LIBC_NAMESPACE; |
20 | |
21 | // The design for the printf parser fuzzer is fairly simple. The parser uses a |
22 | // mock arg list that will never fail, and is passed a randomized string. The |
23 | // format sections it outputs are checked against a count of the number of '%' |
24 | // signs are in the original string. This is a fairly basic test, and the main |
25 | // intent is to run this under sanitizers, which will check for buffer overruns. |
26 | extern "C"int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
27 | char *in_str = new char[size + 1]; |
28 | |
29 | for (size_t i = 0; i < size; ++i) |
30 | in_str[i] = data[i]; |
31 | |
32 | in_str[size] = '\0'; |
33 | |
34 | auto mock_arg_list = internal::MockArgList(); |
35 | |
36 | auto parser = |
37 | printf_core::Parser<internal::MockArgList>(in_str, mock_arg_list); |
38 | |
39 | int str_percent_count = 0; |
40 | |
41 | for (size_t i = 0; i < size && in_str[i] != '\0'; ++i) { |
42 | if (in_str[i] == '%') { |
43 | ++str_percent_count; |
44 | } |
45 | } |
46 | |
47 | int section_percent_count = 0; |
48 | |
49 | for (printf_core::FormatSection cur_section = parser.get_next_section(); |
50 | !cur_section.raw_string.empty(); |
51 | cur_section = parser.get_next_section()) { |
52 | if (cur_section.has_conv) { |
53 | ++section_percent_count; |
54 | if (cur_section.conv_name == '%') { |
55 | ++section_percent_count; |
56 | } |
57 | } else if (cur_section.raw_string[0] == '%') { |
58 | // If the conversion would be undefined, it's instead raw, but it still |
59 | // starts with a %. |
60 | ++section_percent_count; |
61 | } |
62 | } |
63 | |
64 | if (str_percent_count != section_percent_count) { |
65 | __builtin_trap(); |
66 | } |
67 | |
68 | delete[] in_str; |
69 | return 0; |
70 | } |
71 |