]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/compiler-rt/lib/fuzzer/FuzzerCommand.h
Merge clang 7.0.1 and several follow-up changes
[FreeBSD/FreeBSD.git] / contrib / compiler-rt / lib / fuzzer / FuzzerCommand.h
1 //===- 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
24 namespace fuzzer {
25
26 class Command final {
27 public:
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.
31   static inline const char *ignoreRemainingArgs() {
32     return "-ignore_remaining_args=1";
33   }
34
35   Command() : CombinedOutAndErr(false) {}
36
37   explicit Command(const Vector<std::string> &ArgsToAdd)
38       : Args(ArgsToAdd), CombinedOutAndErr(false) {}
39
40   explicit Command(const Command &Other)
41       : Args(Other.Args), CombinedOutAndErr(Other.CombinedOutAndErr),
42         OutputFile(Other.OutputFile) {}
43
44   Command &operator=(const Command &Other) {
45     Args = Other.Args;
46     CombinedOutAndErr = Other.CombinedOutAndErr;
47     OutputFile = Other.OutputFile;
48     return *this;
49   }
50
51   ~Command() {}
52
53   // Returns true if the given Arg is present in Args.  Only checks up to
54   // "-ignore_remaining_args=1".
55   bool hasArgument(const std::string &Arg) const {
56     auto i = endMutableArgs();
57     return std::find(Args.begin(), i, Arg) != i;
58   }
59
60   // Gets all of the current command line arguments, **including** those after
61   // "-ignore-remaining-args=1".
62   const Vector<std::string> &getArguments() const { return Args; }
63
64   // Adds the given argument before "-ignore_remaining_args=1", or at the end
65   // if that flag isn't present.
66   void addArgument(const std::string &Arg) {
67     Args.insert(endMutableArgs(), Arg);
68   }
69
70   // Adds all given arguments before "-ignore_remaining_args=1", or at the end
71   // if that flag isn't present.
72   void addArguments(const Vector<std::string> &ArgsToAdd) {
73     Args.insert(endMutableArgs(), ArgsToAdd.begin(), ArgsToAdd.end());
74   }
75
76   // Removes the given argument from the command argument list.  Ignores any
77   // occurrences after "-ignore_remaining_args=1", if present.
78   void removeArgument(const std::string &Arg) {
79     auto i = endMutableArgs();
80     Args.erase(std::remove(Args.begin(), i, Arg), i);
81   }
82
83   // Like hasArgument, but checks for "-[Flag]=...".
84   bool hasFlag(const std::string &Flag) {
85     std::string Arg("-" + Flag + "=");
86     auto IsMatch = [&](const std::string &Other) {
87       return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0;
88     };
89     return std::any_of(Args.begin(), endMutableArgs(), IsMatch);
90   }
91
92   // Returns the value of the first instance of a given flag, or an empty string
93   // if the flag isn't present.  Ignores any occurrences after
94   // "-ignore_remaining_args=1", if present.
95   std::string getFlagValue(const std::string &Flag) {
96     std::string Arg("-" + Flag + "=");
97     auto IsMatch = [&](const std::string &Other) {
98       return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0;
99     };
100     auto i = endMutableArgs();
101     auto j = std::find_if(Args.begin(), i, IsMatch);
102     std::string result;
103     if (j != i) {
104       result = j->substr(Arg.length());
105     }
106     return result;
107   }
108
109   // Like AddArgument, but adds "-[Flag]=[Value]".
110   void addFlag(const std::string &Flag, const std::string &Value) {
111     addArgument("-" + Flag + "=" + Value);
112   }
113
114   // Like RemoveArgument, but removes "-[Flag]=...".
115   void removeFlag(const std::string &Flag) {
116     std::string Arg("-" + Flag + "=");
117     auto IsMatch = [&](const std::string &Other) {
118       return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0;
119     };
120     auto i = endMutableArgs();
121     Args.erase(std::remove_if(Args.begin(), i, IsMatch), i);
122   }
123
124   // Returns whether the command's stdout is being written to an output file.
125   bool hasOutputFile() const { return !OutputFile.empty(); }
126
127   // Returns the currently set output file.
128   const std::string &getOutputFile() const { return OutputFile; }
129
130   // Configures the command to redirect its output to the name file.
131   void setOutputFile(const std::string &FileName) { OutputFile = FileName; }
132
133   // Returns whether the command's stderr is redirected to stdout.
134   bool isOutAndErrCombined() const { return CombinedOutAndErr; }
135
136   // Sets whether to redirect the command's stderr to its stdout.
137   void combineOutAndErr(bool combine = true) { CombinedOutAndErr = combine; }
138
139   // Returns a string representation of the command.  On many systems this will
140   // be the equivalent command line.
141   std::string toString() const {
142     std::stringstream SS;
143     for (auto arg : getArguments())
144       SS << arg << " ";
145     if (hasOutputFile())
146       SS << ">" << getOutputFile() << " ";
147     if (isOutAndErrCombined())
148       SS << "2>&1 ";
149     std::string result = SS.str();
150     if (!result.empty())
151       result = result.substr(0, result.length() - 1);
152     return result;
153   }
154
155 private:
156   Command(Command &&Other) = delete;
157   Command &operator=(Command &&Other) = delete;
158
159   Vector<std::string>::iterator endMutableArgs() {
160     return std::find(Args.begin(), Args.end(), ignoreRemainingArgs());
161   }
162
163   Vector<std::string>::const_iterator endMutableArgs() const {
164     return std::find(Args.begin(), Args.end(), ignoreRemainingArgs());
165   }
166
167   // The command arguments.  Args[0] is the command name.
168   Vector<std::string> Args;
169
170   // True indicates stderr is redirected to stdout.
171   bool CombinedOutAndErr;
172
173   // If not empty, stdout is redirected to the named file.
174   std::string OutputFile;
175 };
176
177 } // namespace fuzzer
178
179 #endif // LLVM_FUZZER_COMMAND_H