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