Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/tools/fuzzing/libfuzzer/FuzzerCommand.h
Line
Count
Source (jump to first uncovered line)
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
0
  static inline const char *ignoreRemainingArgs() {
32
0
    return "-ignore_remaining_args=1";
33
0
  }
34
35
0
  Command() : CombinedOutAndErr(false) {}
36
37
  explicit Command(const Vector<std::string> &ArgsToAdd)
38
0
      : Args(ArgsToAdd), CombinedOutAndErr(false) {}
39
40
  explicit Command(const Command &Other)
41
      : Args(Other.Args), CombinedOutAndErr(Other.CombinedOutAndErr),
42
0
        OutputFile(Other.OutputFile) {}
43
44
0
  Command &operator=(const Command &Other) {
45
0
    Args = Other.Args;
46
0
    CombinedOutAndErr = Other.CombinedOutAndErr;
47
0
    OutputFile = Other.OutputFile;
48
0
    return *this;
49
0
  }
50
51
0
  ~Command() {}
52
53
  // Returns true if the given Arg is present in Args.  Only checks up to
54
  // "-ignore_remaining_args=1".
55
0
  bool hasArgument(const std::string &Arg) const {
56
0
    auto i = endMutableArgs();
57
0
    return std::find(Args.begin(), i, Arg) != i;
58
0
  }
59
60
  // Gets all of the current command line arguments, **including** those after
61
  // "-ignore-remaining-args=1".
62
0
  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
0
  void addArgument(const std::string &Arg) {
67
0
    Args.insert(endMutableArgs(), Arg);
68
0
  }
69
70
  // Adds all given arguments before "-ignore_remaining_args=1", or at the end
71
  // if that flag isn't present.
72
0
  void addArguments(const Vector<std::string> &ArgsToAdd) {
73
0
    Args.insert(endMutableArgs(), ArgsToAdd.begin(), ArgsToAdd.end());
74
0
  }
75
76
  // Removes the given argument from the command argument list.  Ignores any
77
  // occurrences after "-ignore_remaining_args=1", if present.
78
0
  void removeArgument(const std::string &Arg) {
79
0
    auto i = endMutableArgs();
80
0
    Args.erase(std::remove(Args.begin(), i, Arg), i);
81
0
  }
82
83
  // Like hasArgument, but checks for "-[Flag]=...".
84
0
  bool hasFlag(const std::string &Flag) {
85
0
    std::string Arg("-" + Flag + "=");
86
0
    auto IsMatch = [&](const std::string &Other) {
87
0
      return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0;
88
0
    };
89
0
    return std::any_of(Args.begin(), endMutableArgs(), IsMatch);
90
0
  }
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
0
  std::string getFlagValue(const std::string &Flag) {
96
0
    std::string Arg("-" + Flag + "=");
97
0
    auto IsMatch = [&](const std::string &Other) {
98
0
      return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0;
99
0
    };
100
0
    auto i = endMutableArgs();
101
0
    auto j = std::find_if(Args.begin(), i, IsMatch);
102
0
    std::string result;
103
0
    if (j != i) {
104
0
      result = j->substr(Arg.length());
105
0
    }
106
0
    return result;
107
0
  }
108
109
  // Like AddArgument, but adds "-[Flag]=[Value]".
110
0
  void addFlag(const std::string &Flag, const std::string &Value) {
111
0
    addArgument("-" + Flag + "=" + Value);
112
0
  }
113
114
  // Like RemoveArgument, but removes "-[Flag]=...".
115
0
  void removeFlag(const std::string &Flag) {
116
0
    std::string Arg("-" + Flag + "=");
117
0
    auto IsMatch = [&](const std::string &Other) {
118
0
      return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0;
119
0
    };
120
0
    auto i = endMutableArgs();
121
0
    Args.erase(std::remove_if(Args.begin(), i, IsMatch), i);
122
0
  }
123
124
  // Returns whether the command's stdout is being written to an output file.
125
0
  bool hasOutputFile() const { return !OutputFile.empty(); }
126
127
  // Returns the currently set output file.
128
0
  const std::string &getOutputFile() const { return OutputFile; }
129
130
  // Configures the command to redirect its output to the name file.
131
0
  void setOutputFile(const std::string &FileName) { OutputFile = FileName; }
132
133
  // Returns whether the command's stderr is redirected to stdout.
134
0
  bool isOutAndErrCombined() const { return CombinedOutAndErr; }
135
136
  // Sets whether to redirect the command's stderr to its stdout.
137
0
  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
0
  std::string toString() const {
142
0
    std::stringstream SS;
143
0
    for (auto arg : getArguments())
144
0
      SS << arg << " ";
145
0
    if (hasOutputFile())
146
0
      SS << ">" << getOutputFile() << " ";
147
0
    if (isOutAndErrCombined())
148
0
      SS << "2>&1 ";
149
0
    std::string result = SS.str();
150
0
    if (!result.empty())
151
0
      result = result.substr(0, result.length() - 1);
152
0
    return result;
153
0
  }
154
155
private:
156
  Command(Command &&Other) = delete;
157
  Command &operator=(Command &&Other) = delete;
158
159
0
  Vector<std::string>::iterator endMutableArgs() {
160
0
    return std::find(Args.begin(), Args.end(), ignoreRemainingArgs());
161
0
  }
162
163
0
  Vector<std::string>::const_iterator endMutableArgs() const {
164
0
    return std::find(Args.begin(), Args.end(), ignoreRemainingArgs());
165
0
  }
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