• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Tint Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <cstddef>
16 #include <cstdint>
17 
18 #include "fuzzers/random_generator.h"
19 #include "fuzzers/tint_ast_fuzzer/cli.h"
20 #include "fuzzers/tint_ast_fuzzer/mutator.h"
21 #include "fuzzers/tint_ast_fuzzer/override_cli_params.h"
22 #include "fuzzers/tint_common_fuzzer.h"
23 #include "fuzzers/transform_builder.h"
24 
25 #include "src/reader/wgsl/parser.h"
26 #include "src/writer/wgsl/generator.h"
27 
28 namespace tint {
29 namespace fuzzers {
30 namespace ast_fuzzer {
31 namespace {
32 
33 CliParams cli_params{};
34 
LLVMFuzzerInitialize(int * argc,char *** argv)35 extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
36   // Parse CLI parameters. `ParseCliParams` will call `exit` if some parameter
37   // is invalid.
38   cli_params = ParseCliParams(argc, *argv);
39   // For some fuzz targets it is desirable to force the values of certain CLI
40   // parameters after parsing.
41   OverrideCliParams(cli_params);
42   return 0;
43 }
44 
LLVMFuzzerCustomMutator(uint8_t * data,size_t size,size_t max_size,unsigned seed)45 extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data,
46                                           size_t size,
47                                           size_t max_size,
48                                           unsigned seed) {
49   Source::File file("test.wgsl", {reinterpret_cast<char*>(data), size});
50   auto program = reader::wgsl::Parse(&file);
51   if (!program.IsValid()) {
52     std::cout << "Trying to mutate an invalid program:" << std::endl
53               << program.Diagnostics().str() << std::endl;
54     return 0;
55   }
56 
57   // Run the mutator.
58   RandomGenerator generator(seed);
59   ProbabilityContext probability_context(&generator);
60   program = Mutate(std::move(program), &probability_context,
61                    cli_params.enable_all_mutations,
62                    cli_params.mutation_batch_size, nullptr);
63 
64   if (!program.IsValid()) {
65     std::cout << "Mutator produced invalid WGSL:" << std::endl
66               << "  seed: " << seed << std::endl
67               << program.Diagnostics().str() << std::endl;
68     return 0;
69   }
70 
71   auto result = writer::wgsl::Generate(&program, writer::wgsl::Options());
72   if (!result.success) {
73     std::cout << "Can't generate WGSL for a valid tint::Program:" << std::endl
74               << result.error << std::endl;
75     return 0;
76   }
77 
78   if (result.wgsl.size() > max_size) {
79     return 0;
80   }
81 
82   // No need to worry about the \0 here. The reason is that if \0 is included by
83   // developer by mistake, it will be considered a part of the string and will
84   // cause all sorts of strange bugs. Thus, unless `data` below is used as a raw
85   // C string, the \0 symbol should be ignored.
86   std::memcpy(  // NOLINT - clang-tidy warns about lack of null termination.
87       data, result.wgsl.data(), result.wgsl.size());
88   return result.wgsl.size();
89 }
90 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)91 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
92   if (size == 0) {
93     return 0;
94   }
95 
96   struct Target {
97     FuzzingTarget fuzzing_target;
98     OutputFormat output_format;
99     const char* name;
100   };
101 
102   Target targets[] = {{FuzzingTarget::kWgsl, OutputFormat::kWGSL, "WGSL"},
103                       {FuzzingTarget::kHlsl, OutputFormat::kHLSL, "HLSL"},
104                       {FuzzingTarget::kMsl, OutputFormat::kMSL, "MSL"},
105                       {FuzzingTarget::kSpv, OutputFormat::kSpv, "SPV"}};
106 
107   for (auto target : targets) {
108     if ((target.fuzzing_target & cli_params.fuzzing_target) !=
109         target.fuzzing_target) {
110       continue;
111     }
112 
113     TransformBuilder tb(data, size);
114     tb.AddTransform<tint::transform::Robustness>();
115 
116     CommonFuzzer fuzzer(InputFormat::kWGSL, target.output_format);
117     fuzzer.SetTransformManager(tb.manager(), tb.data_map());
118 
119     fuzzer.Run(data, size);
120     if (fuzzer.HasErrors()) {
121       std::cout << "Fuzzing " << target.name << " produced an error"
122                 << std::endl;
123       auto printer = tint::diag::Printer::create(stderr, true);
124       tint::diag::Formatter{}.format(fuzzer.Diagnostics(), printer.get());
125     }
126   }
127 
128   return 0;
129 }
130 
131 }  // namespace
132 }  // namespace ast_fuzzer
133 }  // namespace fuzzers
134 }  // namespace tint
135