1 //===- FuzzerCommand.h - Interface representing a process -------*- C++ -* ===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
8 // FuzzerCommand represents a command to run in a subprocess. It allows callers
9 // to manage command line arguments and output and error streams.
10 //===----------------------------------------------------------------------===//
12 #ifndef LLVM_FUZZER_COMMAND_H
13 #define LLVM_FUZZER_COMMAND_H
15 #include "FuzzerDefs.h"
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
31 static inline const char *ignoreRemainingArgs() {
32 return "-ignore_remaining_args=1";
35 Command() : CombinedOutAndErr(false) {}
37 explicit Command(const std::vector
<std::string
> &ArgsToAdd
)
38 : Args(ArgsToAdd
), CombinedOutAndErr(false) {}
40 explicit Command(const Command
&Other
)
41 : Args(Other
.Args
), CombinedOutAndErr(Other
.CombinedOutAndErr
),
42 OutputFile(Other
.OutputFile
) {}
44 Command
&operator=(const Command
&Other
) {
46 CombinedOutAndErr
= Other
.CombinedOutAndErr
;
47 OutputFile
= Other
.OutputFile
;
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
;
60 // Gets all of the current command line arguments, **including** those after
61 // "-ignore-remaining-args=1".
62 const std::vector
<std::string
> &getArguments() const { return Args
; }
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
);
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 std::vector
<std::string
> &ArgsToAdd
) {
73 Args
.insert(endMutableArgs(), ArgsToAdd
.begin(), ArgsToAdd
.end());
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
);
83 // Like hasArgument, but checks for "-[Flag]=...".
84 bool hasFlag(const std::string
&Flag
) const {
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;
89 return std::any_of(Args
.begin(), endMutableArgs(), IsMatch
);
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
) const {
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;
100 auto i
= endMutableArgs();
101 auto j
= std::find_if(Args
.begin(), i
, IsMatch
);
104 result
= j
->substr(Arg
.length());
109 // Like AddArgument, but adds "-[Flag]=[Value]".
110 void addFlag(const std::string
&Flag
, const std::string
&Value
) {
111 addArgument("-" + Flag
+ "=" + Value
);
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;
120 auto i
= endMutableArgs();
121 Args
.erase(std::remove_if(Args
.begin(), i
, IsMatch
), i
);
124 // Returns whether the command's stdout is being written to an output file.
125 bool hasOutputFile() const { return !OutputFile
.empty(); }
127 // Returns the currently set output file.
128 const std::string
&getOutputFile() const { return OutputFile
; }
130 // Configures the command to redirect its output to the name file.
131 void setOutputFile(const std::string
&FileName
) { OutputFile
= FileName
; }
133 // Returns whether the command's stderr is redirected to stdout.
134 bool isOutAndErrCombined() const { return CombinedOutAndErr
; }
136 // Sets whether to redirect the command's stderr to its stdout.
137 void combineOutAndErr(bool combine
= true) { CombinedOutAndErr
= combine
; }
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 (const auto &arg
: getArguments())
146 SS
<< ">" << getOutputFile() << " ";
147 if (isOutAndErrCombined())
149 std::string result
= SS
.str();
151 result
= result
.substr(0, result
.length() - 1);
156 Command(Command
&&Other
) = delete;
157 Command
&operator=(Command
&&Other
) = delete;
159 std::vector
<std::string
>::iterator
endMutableArgs() {
160 return std::find(Args
.begin(), Args
.end(), ignoreRemainingArgs());
163 std::vector
<std::string
>::const_iterator
endMutableArgs() const {
164 return std::find(Args
.begin(), Args
.end(), ignoreRemainingArgs());
167 // The command arguments. Args[0] is the command name.
168 std::vector
<std::string
> Args
;
170 // True indicates stderr is redirected to stdout.
171 bool CombinedOutAndErr
;
173 // If not empty, stdout is redirected to the named file.
174 std::string OutputFile
;
177 } // namespace fuzzer
179 #endif // LLVM_FUZZER_COMMAND_H