1 1.1 kamil //===- FuzzerCommand.h - Interface representing a process -------*- C++ -* ===// 2 1.1 kamil // 3 1.1 kamil // The LLVM Compiler Infrastructure 4 1.1 kamil // 5 1.1 kamil // This file is distributed under the University of Illinois Open Source 6 1.1 kamil // License. See LICENSE.TXT for details. 7 1.1 kamil // 8 1.1 kamil //===----------------------------------------------------------------------===// 9 1.1 kamil // FuzzerCommand represents a command to run in a subprocess. It allows callers 10 1.1 kamil // to manage command line arguments and output and error streams. 11 1.1 kamil //===----------------------------------------------------------------------===// 12 1.1 kamil 13 1.1 kamil #ifndef LLVM_FUZZER_COMMAND_H 14 1.1 kamil #define LLVM_FUZZER_COMMAND_H 15 1.1 kamil 16 1.1 kamil #include "FuzzerDefs.h" 17 1.1 kamil #include "FuzzerIO.h" 18 1.1 kamil 19 1.1 kamil #include <algorithm> 20 1.1 kamil #include <sstream> 21 1.1 kamil #include <string> 22 1.1 kamil #include <vector> 23 1.1 kamil 24 1.1 kamil namespace fuzzer { 25 1.1 kamil 26 1.1 kamil class Command final { 27 1.1 kamil public: 28 1.1 kamil // This command line flag is used to indicate that the remaining command line 29 1.1 kamil // is immutable, meaning this flag effectively marks the end of the mutable 30 1.1 kamil // argument list. 31 1.1 kamil static inline const char *ignoreRemainingArgs() { 32 1.1 kamil return "-ignore_remaining_args=1"; 33 1.1 kamil } 34 1.1 kamil 35 1.1 kamil Command() : CombinedOutAndErr(false) {} 36 1.1 kamil 37 1.1 kamil explicit Command(const Vector<std::string> &ArgsToAdd) 38 1.1 kamil : Args(ArgsToAdd), CombinedOutAndErr(false) {} 39 1.1 kamil 40 1.1 kamil explicit Command(const Command &Other) 41 1.1 kamil : Args(Other.Args), CombinedOutAndErr(Other.CombinedOutAndErr), 42 1.1 kamil OutputFile(Other.OutputFile) {} 43 1.1 kamil 44 1.1 kamil Command &operator=(const Command &Other) { 45 1.1 kamil Args = Other.Args; 46 1.1 kamil CombinedOutAndErr = Other.CombinedOutAndErr; 47 1.1 kamil OutputFile = Other.OutputFile; 48 1.1 kamil return *this; 49 1.1 kamil } 50 1.1 kamil 51 1.1 kamil ~Command() {} 52 1.1 kamil 53 1.1 kamil // Returns true if the given Arg is present in Args. Only checks up to 54 1.1 kamil // "-ignore_remaining_args=1". 55 1.1 kamil bool hasArgument(const std::string &Arg) const { 56 1.1 kamil auto i = endMutableArgs(); 57 1.1 kamil return std::find(Args.begin(), i, Arg) != i; 58 1.1 kamil } 59 1.1 kamil 60 1.1 kamil // Gets all of the current command line arguments, **including** those after 61 1.1 kamil // "-ignore-remaining-args=1". 62 1.1 kamil const Vector<std::string> &getArguments() const { return Args; } 63 1.1 kamil 64 1.1 kamil // Adds the given argument before "-ignore_remaining_args=1", or at the end 65 1.1 kamil // if that flag isn't present. 66 1.1 kamil void addArgument(const std::string &Arg) { 67 1.1 kamil Args.insert(endMutableArgs(), Arg); 68 1.1 kamil } 69 1.1 kamil 70 1.1 kamil // Adds all given arguments before "-ignore_remaining_args=1", or at the end 71 1.1 kamil // if that flag isn't present. 72 1.1 kamil void addArguments(const Vector<std::string> &ArgsToAdd) { 73 1.1 kamil Args.insert(endMutableArgs(), ArgsToAdd.begin(), ArgsToAdd.end()); 74 1.1 kamil } 75 1.1 kamil 76 1.1 kamil // Removes the given argument from the command argument list. Ignores any 77 1.1 kamil // occurrences after "-ignore_remaining_args=1", if present. 78 1.1 kamil void removeArgument(const std::string &Arg) { 79 1.1 kamil auto i = endMutableArgs(); 80 1.1 kamil Args.erase(std::remove(Args.begin(), i, Arg), i); 81 1.1 kamil } 82 1.1 kamil 83 1.1 kamil // Like hasArgument, but checks for "-[Flag]=...". 84 1.1 kamil bool hasFlag(const std::string &Flag) const { 85 1.1 kamil std::string Arg("-" + Flag + "="); 86 1.1 kamil auto IsMatch = [&](const std::string &Other) { 87 1.1 kamil return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0; 88 1.1 kamil }; 89 1.1 kamil return std::any_of(Args.begin(), endMutableArgs(), IsMatch); 90 1.1 kamil } 91 1.1 kamil 92 1.1 kamil // Returns the value of the first instance of a given flag, or an empty string 93 1.1 kamil // if the flag isn't present. Ignores any occurrences after 94 1.1 kamil // "-ignore_remaining_args=1", if present. 95 1.1 kamil std::string getFlagValue(const std::string &Flag) const { 96 1.1 kamil std::string Arg("-" + Flag + "="); 97 1.1 kamil auto IsMatch = [&](const std::string &Other) { 98 1.1 kamil return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0; 99 1.1 kamil }; 100 1.1 kamil auto i = endMutableArgs(); 101 1.1 kamil auto j = std::find_if(Args.begin(), i, IsMatch); 102 1.1 kamil std::string result; 103 1.1 kamil if (j != i) { 104 1.1 kamil result = j->substr(Arg.length()); 105 1.1 kamil } 106 1.1 kamil return result; 107 1.1 kamil } 108 1.1 kamil 109 1.1 kamil // Like AddArgument, but adds "-[Flag]=[Value]". 110 1.1 kamil void addFlag(const std::string &Flag, const std::string &Value) { 111 1.1 kamil addArgument("-" + Flag + "=" + Value); 112 1.1 kamil } 113 1.1 kamil 114 1.1 kamil // Like RemoveArgument, but removes "-[Flag]=...". 115 1.1 kamil void removeFlag(const std::string &Flag) { 116 1.1 kamil std::string Arg("-" + Flag + "="); 117 1.1 kamil auto IsMatch = [&](const std::string &Other) { 118 1.1 kamil return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0; 119 1.1 kamil }; 120 1.1 kamil auto i = endMutableArgs(); 121 1.1 kamil Args.erase(std::remove_if(Args.begin(), i, IsMatch), i); 122 1.1 kamil } 123 1.1 kamil 124 1.1 kamil // Returns whether the command's stdout is being written to an output file. 125 1.1 kamil bool hasOutputFile() const { return !OutputFile.empty(); } 126 1.1 kamil 127 1.1 kamil // Returns the currently set output file. 128 1.1 kamil const std::string &getOutputFile() const { return OutputFile; } 129 1.1 kamil 130 1.1 kamil // Configures the command to redirect its output to the name file. 131 1.1 kamil void setOutputFile(const std::string &FileName) { OutputFile = FileName; } 132 1.1 kamil 133 1.1 kamil // Returns whether the command's stderr is redirected to stdout. 134 1.1 kamil bool isOutAndErrCombined() const { return CombinedOutAndErr; } 135 1.1 kamil 136 1.1 kamil // Sets whether to redirect the command's stderr to its stdout. 137 1.1 kamil void combineOutAndErr(bool combine = true) { CombinedOutAndErr = combine; } 138 1.1 kamil 139 1.1 kamil // Returns a string representation of the command. On many systems this will 140 1.1 kamil // be the equivalent command line. 141 1.1 kamil std::string toString() const { 142 1.1 kamil std::stringstream SS; 143 1.1 kamil for (auto arg : getArguments()) 144 1.1 kamil SS << arg << " "; 145 1.1 kamil if (hasOutputFile()) 146 1.1 kamil SS << ">" << getOutputFile() << " "; 147 1.1 kamil if (isOutAndErrCombined()) 148 1.1 kamil SS << "2>&1 "; 149 1.1 kamil std::string result = SS.str(); 150 1.1 kamil if (!result.empty()) 151 1.1 kamil result = result.substr(0, result.length() - 1); 152 1.1 kamil return result; 153 1.1 kamil } 154 1.1 kamil 155 1.1 kamil private: 156 1.1 kamil Command(Command &&Other) = delete; 157 1.1 kamil Command &operator=(Command &&Other) = delete; 158 1.1 kamil 159 1.1 kamil Vector<std::string>::iterator endMutableArgs() { 160 1.1 kamil return std::find(Args.begin(), Args.end(), ignoreRemainingArgs()); 161 1.1 kamil } 162 1.1 kamil 163 1.1 kamil Vector<std::string>::const_iterator endMutableArgs() const { 164 1.1 kamil return std::find(Args.begin(), Args.end(), ignoreRemainingArgs()); 165 1.1 kamil } 166 1.1 kamil 167 1.1 kamil // The command arguments. Args[0] is the command name. 168 1.1 kamil Vector<std::string> Args; 169 1.1 kamil 170 1.1 kamil // True indicates stderr is redirected to stdout. 171 1.1 kamil bool CombinedOutAndErr; 172 1.1 kamil 173 1.1 kamil // If not empty, stdout is redirected to the named file. 174 1.1 kamil std::string OutputFile; 175 1.1 kamil }; 176 1.1 kamil 177 1.1 kamil } // namespace fuzzer 178 1.1 kamil 179 1.1 kamil #endif // LLVM_FUZZER_COMMAND_H 180