1 // Copyright 2022 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include <fuzzer/FuzzedDataProvider.h>
12 #include "base/check.h"
13 #include "base/command_line.h"
14 #include "base/files/file_path.h"
15 #include "base/ranges/algorithm.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "build/build_config.h"
24 CommandLine::StringType GenerateNativeString(FuzzedDataProvider& provider) {
25 const std::string raw_string = provider.ConsumeRandomLengthString();
27 return UTF8ToWide(raw_string);
33 CommandLine::StringVector GenerateNativeStringVector(
34 FuzzedDataProvider& provider) {
35 CommandLine::StringVector strings(
36 provider.ConsumeIntegralInRange<int>(0, 100));
37 for (auto& item : strings)
38 item = GenerateNativeString(provider);
42 FilePath GenerateFilePath(FuzzedDataProvider& provider) {
43 return FilePath(GenerateNativeString(provider));
46 bool IsForbiddenSwitchCharacter(char c) {
47 return IsAsciiWhitespace(c) || c == '=' || c != ToLowerASCII(c);
50 bool IsValidSwitchName(const std::string& text) {
51 // This duplicates the logic in command_line.cc, but it's not exposed in form
52 // of public interface.
53 return !text.empty() && !ranges::any_of(text, IsForbiddenSwitchCharacter) &&
54 !StartsWith(text, "-") && !StartsWith(text, "/");
59 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
60 FuzzedDataProvider provider(data, size);
62 // Create a randomly initialized command line.
63 CommandLine command_line(CommandLine::NO_PROGRAM);
64 switch (provider.ConsumeIntegralInRange<int>(0, 3)) {
69 command_line = CommandLine(GenerateFilePath(provider));
72 command_line = CommandLine(GenerateNativeStringVector(provider));
76 command_line.ParseFromString(GenerateNativeString(provider));
81 // Do a few mutations of the command line.
82 while (provider.remaining_bytes() > 0) {
83 switch (provider.ConsumeIntegralInRange<int>(0, 4)) {
86 std::string name = provider.ConsumeRandomLengthString();
87 if (IsValidSwitchName(name)) {
88 CommandLine::StringType value = GenerateNativeString(provider);
89 command_line.AppendSwitchNative(name, value);
90 CHECK(command_line.HasSwitch(name));
91 CHECK(command_line.GetSwitchValueNative(name) == value);
97 std::string name = provider.ConsumeRandomLengthString();
98 if (IsValidSwitchName(name)) {
99 command_line.RemoveSwitch(name);
100 CHECK(!command_line.HasSwitch(name));
101 CHECK(command_line.GetSwitchValueNative(name).empty());
107 CommandLine::StringType arg = GenerateNativeString(provider);
108 if (!arg.empty() && IsStringASCII(arg))
109 command_line.AppendArgNative(arg);
114 CommandLine::StringType wrapper = GenerateNativeString(provider);
115 if (!wrapper.empty())
116 command_line.PrependWrapper(wrapper);
121 std::string name = provider.ConsumeRandomLengthString();
122 if (IsValidSwitchName(name)) {
123 std::ignore = command_line.HasSwitch(name);
124 std::ignore = command_line.GetSwitchValueNative(name);
130 // Smoke-test various accessors.
131 std::ignore = command_line.GetCommandLineString();
132 std::ignore = command_line.GetArgumentsString();
133 #if BUILDFLAG(IS_WIN)
134 std::ignore = command_line.GetCommandLineStringForShell();
135 std::ignore = command_line.GetCommandLineStringWithUnsafeInsertSequences();