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"
27 // This command line flag is used to indicate that the remaining command line
28 // is immutable, meaning this flag effectively marks the end of the mutable
30 static inline const char *ignoreRemainingArgs() {
31 return "-ignore_remaining_args=1";
34 Command() : CombinedOutAndErr(false) {}
36 explicit Command(const Vector
<std::string
> &ArgsToAdd
)
37 : Args(ArgsToAdd
), CombinedOutAndErr(false) {}
39 explicit Command(const Command
&Other
)
40 : Args(Other
.Args
), CombinedOutAndErr(Other
.CombinedOutAndErr
),
41 OutputFile(Other
.OutputFile
) {}
43 Command
&operator=(const Command
&Other
) {
45 CombinedOutAndErr
= Other
.CombinedOutAndErr
;
46 OutputFile
= Other
.OutputFile
;
52 // Returns true if the given Arg is present in Args. Only checks up to
53 // "-ignore_remaining_args=1".
54 bool hasArgument(const std::string
&Arg
) const {
55 auto i
= endMutableArgs();
56 return std::find(Args
.begin(), i
, Arg
) != i
;
59 // Gets all of the current command line arguments, **including** those after
60 // "-ignore-remaining-args=1".
61 const Vector
<std::string
> &getArguments() const { return Args
; }
63 // Adds the given argument before "-ignore_remaining_args=1", or at the end
64 // if that flag isn't present.
65 void addArgument(const std::string
&Arg
) {
66 Args
.insert(endMutableArgs(), Arg
);
69 // Adds all given arguments before "-ignore_remaining_args=1", or at the end
70 // if that flag isn't present.
71 void addArguments(const Vector
<std::string
> &ArgsToAdd
) {
72 Args
.insert(endMutableArgs(), ArgsToAdd
.begin(), ArgsToAdd
.end());
75 // Removes the given argument from the command argument list. Ignores any
76 // occurrences after "-ignore_remaining_args=1", if present.
77 void removeArgument(const std::string
&Arg
) {
78 auto i
= endMutableArgs();
79 Args
.erase(std::remove(Args
.begin(), i
, Arg
), i
);
82 // Like hasArgument, but checks for "-[Flag]=...".
83 bool hasFlag(const std::string
&Flag
) const {
84 std::string
Arg("-" + Flag
+ "=");
85 auto IsMatch
= [&](const std::string
&Other
) {
86 return Arg
.compare(0, std::string::npos
, Other
, 0, Arg
.length()) == 0;
88 return std::any_of(Args
.begin(), endMutableArgs(), IsMatch
);
91 // Returns the value of the first instance of a given flag, or an empty string
92 // if the flag isn't present. Ignores any occurrences after
93 // "-ignore_remaining_args=1", if present.
94 std::string
getFlagValue(const std::string
&Flag
) const {
95 std::string
Arg("-" + Flag
+ "=");
96 auto IsMatch
= [&](const std::string
&Other
) {
97 return Arg
.compare(0, std::string::npos
, Other
, 0, Arg
.length()) == 0;
99 auto i
= endMutableArgs();
100 auto j
= std::find_if(Args
.begin(), i
, IsMatch
);
103 result
= j
->substr(Arg
.length());
108 // Like AddArgument, but adds "-[Flag]=[Value]".
109 void addFlag(const std::string
&Flag
, const std::string
&Value
) {
110 addArgument("-" + Flag
+ "=" + Value
);
113 // Like RemoveArgument, but removes "-[Flag]=...".
114 void removeFlag(const std::string
&Flag
) {
115 std::string
Arg("-" + Flag
+ "=");
116 auto IsMatch
= [&](const std::string
&Other
) {
117 return Arg
.compare(0, std::string::npos
, Other
, 0, Arg
.length()) == 0;
119 auto i
= endMutableArgs();
120 Args
.erase(std::remove_if(Args
.begin(), i
, IsMatch
), i
);
123 // Returns whether the command's stdout is being written to an output file.
124 bool hasOutputFile() const { return !OutputFile
.empty(); }
126 // Returns the currently set output file.
127 const std::string
&getOutputFile() const { return OutputFile
; }
129 // Configures the command to redirect its output to the name file.
130 void setOutputFile(const std::string
&FileName
) { OutputFile
= FileName
; }
132 // Returns whether the command's stderr is redirected to stdout.
133 bool isOutAndErrCombined() const { return CombinedOutAndErr
; }
135 // Sets whether to redirect the command's stderr to its stdout.
136 void combineOutAndErr(bool combine
= true) { CombinedOutAndErr
= combine
; }
138 // Returns a string representation of the command. On many systems this will
139 // be the equivalent command line.
140 std::string
toString() const {
141 std::stringstream SS
;
142 for (auto arg
: getArguments())
145 SS
<< ">" << getOutputFile() << " ";
146 if (isOutAndErrCombined())
148 std::string result
= SS
.str();
150 result
= result
.substr(0, result
.length() - 1);
155 Command(Command
&&Other
) = delete;
156 Command
&operator=(Command
&&Other
) = delete;
158 Vector
<std::string
>::iterator
endMutableArgs() {
159 return std::find(Args
.begin(), Args
.end(), ignoreRemainingArgs());
162 Vector
<std::string
>::const_iterator
endMutableArgs() const {
163 return std::find(Args
.begin(), Args
.end(), ignoreRemainingArgs());
166 // The command arguments. Args[0] is the command name.
167 Vector
<std::string
> Args
;
169 // True indicates stderr is redirected to stdout.
170 bool CombinedOutAndErr
;
172 // If not empty, stdout is redirected to the named file.
173 std::string OutputFile
;
176 } // namespace fuzzer
178 #endif // LLVM_FUZZER_COMMAND_H