Add ICU message format support
[chromium-blink-merge.git] / tools / ipc_fuzzer / fuzzer / fuzzer_main.cc
blobb92e44aa8e56b3207f47ef707c68be3a8fa73839
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include <iostream>
6 #include <set>
7 #include <vector>
9 #include "base/command_line.h"
10 #include "base/strings/string_split.h"
11 #include "ipc/ipc_message_macros.h"
12 #include "tools/ipc_fuzzer/fuzzer/fuzzer.h"
13 #include "tools/ipc_fuzzer/fuzzer/generator.h"
14 #include "tools/ipc_fuzzer/fuzzer/mutator.h"
15 #include "tools/ipc_fuzzer/fuzzer/rand_util.h"
16 #include "tools/ipc_fuzzer/message_lib/message_file.h"
18 namespace ipc_fuzzer {
20 namespace {
22 // TODO(mbarbella): Check to see if this value is actually reasonable.
23 const int kFrequency = 23;
25 const char kCountSwitch[] = "count";
26 const char kCountSwitchHelp[] =
27 "Number of messages to generate (generator).";
29 const char kFrequencySwitch[] = "frequency";
30 const char kFrequencySwitchHelp[] =
31 "Probability of mutation; tweak every 1/|q| times (mutator).";
33 const char kFuzzerNameSwitch[] = "fuzzer-name";
34 const char kFuzzerNameSwitchHelp[] =
35 "Select generator, mutator, or no-op fuzzer. Default: generator";
37 const char kHelpSwitch[] = "help";
38 const char kHelpSwitchHelp[] =
39 "Show this message.";
41 const char kPermuteSwitch[] = "permute";
42 const char kPermuteSwitchHelp[] =
43 "Randomly shuffle the order of all messages (mutator).";
45 const char kTypeListSwitch[] = "type-list";
46 const char kTypeListSwitchHelp[] =
47 "Explicit list of the only message-ids to mutate (mutator).";
49 void usage() {
50 std::cerr << "Mutate messages from an exiting message file.\n";
52 std::cerr << "Usage:\n"
53 << " ipc_fuzzer"
54 << " [--" << kCountSwitch << "=c]"
55 << " [--" << kFrequencySwitch << "=q]"
56 << " [--" << kFuzzerNameSwitch << "=f]"
57 << " [--" << kHelpSwitch << "]"
58 << " [--" << kTypeListSwitch << "=x,y,z...]"
59 << " [--" << kPermuteSwitch << "]"
60 << " [infile (mutation only)] outfile\n";
62 std::cerr
63 << " --" << kCountSwitch << " - " << kCountSwitchHelp << "\n"
64 << " --" << kFrequencySwitch << " - " << kFrequencySwitchHelp << "\n"
65 << " --" << kFuzzerNameSwitch << " - " << kFuzzerNameSwitchHelp << "\n"
66 << " --" << kHelpSwitch << " - " << kHelpSwitchHelp << "\n"
67 << " --" << kTypeListSwitch << " - " << kTypeListSwitchHelp << "\n"
68 << " --" << kPermuteSwitch << " - " << kPermuteSwitchHelp << "\n";
71 } // namespace
73 class FuzzerFactory {
74 public:
75 static Fuzzer *Create(const std::string& name, int frequency) {
76 if (name == "default")
77 return new Generator();
79 if (name == "generate")
80 return new Generator();
82 if (name == "mutate")
83 return new Mutator(frequency);
85 if (name == "no-op")
86 return new NoOpFuzzer();
88 std::cerr << "No such fuzzer: " << name << "\n";
89 return 0;
93 static IPC::Message* RewriteMessage(
94 IPC::Message* message,
95 Fuzzer* fuzzer,
96 FuzzerFunctionMap* map) {
97 FuzzerFunctionMap::iterator it = map->find(message->type());
98 if (it == map->end()) {
99 // This usually indicates a missing message file in all_messages.h, or
100 // that the message dump file is taken from a different revision of
101 // chromium from this executable.
102 std::cerr << "Unknown message type: ["
103 << IPC_MESSAGE_ID_CLASS(message->type()) << ", "
104 << IPC_MESSAGE_ID_LINE(message->type()) << "].\n";
105 return 0;
108 return (*it->second)(message, fuzzer);
111 int Generate(base::CommandLine* cmd, Fuzzer* fuzzer) {
112 base::CommandLine::StringVector args = cmd->GetArgs();
113 if (args.size() != 1) {
114 usage();
115 return EXIT_FAILURE;
117 base::FilePath::StringType output_file_name = args[0];
119 int message_count = 1000;
120 if (cmd->HasSwitch(kCountSwitch))
121 message_count = atoi(cmd->GetSwitchValueASCII(kCountSwitch).c_str());
123 MessageVector message_vector;
124 int bad_count = 0;
125 if (message_count < 0) {
126 // Enumerate them all.
127 for (size_t i = 0; i < g_function_vector.size(); ++i) {
128 if (IPC::Message* new_message = (*g_function_vector[i])(NULL, fuzzer))
129 message_vector.push_back(new_message);
130 else
131 bad_count += 1;
133 } else {
134 // Fuzz a random batch.
135 for (int i = 0; i < message_count; ++i) {
136 size_t index = RandInRange(g_function_vector.size());
137 if (IPC::Message* new_message = (*g_function_vector[index])(NULL, fuzzer))
138 message_vector.push_back(new_message);
139 else
140 bad_count += 1;
144 std::cerr << "Failed to generate " << bad_count << " messages.\n";
145 if (!MessageFile::Write(base::FilePath(output_file_name), message_vector))
146 return EXIT_FAILURE;
147 return EXIT_SUCCESS;
150 int Mutate(base::CommandLine* cmd, Fuzzer* fuzzer) {
151 base::CommandLine::StringVector args = cmd->GetArgs();
152 if (args.size() != 2) {
153 usage();
154 return EXIT_FAILURE;
156 base::FilePath::StringType input_file_name = args[0];
157 base::FilePath::StringType output_file_name = args[1];
159 bool permute = cmd->HasSwitch(kPermuteSwitch);
161 std::string type_string_list = cmd->GetSwitchValueASCII(kTypeListSwitch);
162 std::vector<std::string> type_string_vector;
163 base::SplitString(type_string_list, ',', &type_string_vector);
164 std::set<uint32> type_set;
165 for (size_t i = 0; i < type_string_vector.size(); ++i) {
166 type_set.insert(atoi(type_string_vector[i].c_str()));
169 FuzzerFunctionMap fuzz_function_map;
170 PopulateFuzzerFunctionMap(&fuzz_function_map);
172 MessageVector message_vector;
173 if (!MessageFile::Read(base::FilePath(input_file_name), &message_vector))
174 return EXIT_FAILURE;
176 for (size_t i = 0; i < message_vector.size(); ++i) {
177 IPC::Message* msg = message_vector[i];
178 // If an explicit type set is specified, make sure we should be mutating
179 // this message type on this run.
180 if (!type_set.empty() && type_set.end() == std::find(
181 type_set.begin(), type_set.end(), msg->type())) {
182 continue;
184 IPC::Message* new_message = RewriteMessage(msg, fuzzer, &fuzz_function_map);
185 if (new_message) {
186 IPC::Message* old_message = message_vector[i];
187 delete old_message;
188 message_vector[i] = new_message;
192 if (permute) {
193 std::random_shuffle(message_vector.begin(), message_vector.end(),
194 RandInRange);
197 if (!MessageFile::Write(base::FilePath(output_file_name), message_vector))
198 return EXIT_FAILURE;
199 return EXIT_SUCCESS;
202 int FuzzerMain(int argc, char** argv) {
203 base::CommandLine::Init(argc, argv);
204 base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
205 base::CommandLine::StringVector args = cmd->GetArgs();
207 if (args.size() == 0 || args.size() > 2 || cmd->HasSwitch(kHelpSwitch)) {
208 usage();
209 return EXIT_FAILURE;
212 InitRand();
214 PopulateFuzzerFunctionVector(&g_function_vector);
215 std::cerr << "Counted " << g_function_vector.size()
216 << " distinct messages present in chrome.\n";
218 std::string fuzzer_name = "default";
219 if (cmd->HasSwitch(kFuzzerNameSwitch))
220 fuzzer_name = cmd->GetSwitchValueASCII(kFuzzerNameSwitch);
222 int frequency = kFrequency;
223 if (cmd->HasSwitch(kFrequencySwitch))
224 frequency = atoi(cmd->GetSwitchValueASCII(kFrequencySwitch).c_str());
226 Fuzzer* fuzzer = FuzzerFactory::Create(fuzzer_name, frequency);
227 if (!fuzzer)
228 return EXIT_FAILURE;
230 int result;
231 base::FilePath::StringType output_file_name;
232 if (fuzzer_name == "default" || fuzzer_name == "generate") {
233 result = Generate(cmd, fuzzer);
234 } else {
235 result = Mutate(cmd, fuzzer);
238 return result;
241 } // namespace ipc_fuzzer
243 int main(int argc, char** argv) {
244 return ipc_fuzzer::FuzzerMain(argc, argv);