FuzzerCommand.h 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. //===- FuzzerCommand.h - Interface representing a process -------*- C++ -* ===//
  2. //
  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
  6. //
  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. //===----------------------------------------------------------------------===//
  11. #ifndef LLVM_FUZZER_COMMAND_H
  12. #define LLVM_FUZZER_COMMAND_H
  13. #include "FuzzerDefs.h"
  14. #include "FuzzerIO.h"
  15. #include <algorithm>
  16. #include <sstream>
  17. #include <string>
  18. #include <vector>
  19. namespace fuzzer {
  20. class Command final {
  21. public:
  22. // This command line flag is used to indicate that the remaining command line
  23. // is immutable, meaning this flag effectively marks the end of the mutable
  24. // argument list.
  25. static inline const char *ignoreRemainingArgs() {
  26. return "-ignore_remaining_args=1";
  27. }
  28. Command() : CombinedOutAndErr(false) {}
  29. explicit Command(const std::vector<std::string> &ArgsToAdd)
  30. : Args(ArgsToAdd), CombinedOutAndErr(false) {}
  31. explicit Command(const Command &Other)
  32. : Args(Other.Args), CombinedOutAndErr(Other.CombinedOutAndErr),
  33. OutputFile(Other.OutputFile) {}
  34. Command &operator=(const Command &Other) {
  35. Args = Other.Args;
  36. CombinedOutAndErr = Other.CombinedOutAndErr;
  37. OutputFile = Other.OutputFile;
  38. return *this;
  39. }
  40. ~Command() {}
  41. // Returns true if the given Arg is present in Args. Only checks up to
  42. // "-ignore_remaining_args=1".
  43. bool hasArgument(const std::string &Arg) const {
  44. auto i = endMutableArgs();
  45. return std::find(Args.begin(), i, Arg) != i;
  46. }
  47. // Gets all of the current command line arguments, **including** those after
  48. // "-ignore-remaining-args=1".
  49. const std::vector<std::string> &getArguments() const { return Args; }
  50. // Adds the given argument before "-ignore_remaining_args=1", or at the end
  51. // if that flag isn't present.
  52. void addArgument(const std::string &Arg) {
  53. Args.insert(endMutableArgs(), Arg);
  54. }
  55. // Adds all given arguments before "-ignore_remaining_args=1", or at the end
  56. // if that flag isn't present.
  57. void addArguments(const std::vector<std::string> &ArgsToAdd) {
  58. Args.insert(endMutableArgs(), ArgsToAdd.begin(), ArgsToAdd.end());
  59. }
  60. // Removes the given argument from the command argument list. Ignores any
  61. // occurrences after "-ignore_remaining_args=1", if present.
  62. void removeArgument(const std::string &Arg) {
  63. auto i = endMutableArgs();
  64. Args.erase(std::remove(Args.begin(), i, Arg), i);
  65. }
  66. // Like hasArgument, but checks for "-[Flag]=...".
  67. bool hasFlag(const std::string &Flag) const {
  68. std::string Arg("-" + Flag + "=");
  69. auto IsMatch = [&](const std::string &Other) {
  70. return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0;
  71. };
  72. return std::any_of(Args.begin(), endMutableArgs(), IsMatch);
  73. }
  74. // Returns the value of the first instance of a given flag, or an empty string
  75. // if the flag isn't present. Ignores any occurrences after
  76. // "-ignore_remaining_args=1", if present.
  77. std::string getFlagValue(const std::string &Flag) const {
  78. std::string Arg("-" + Flag + "=");
  79. auto IsMatch = [&](const std::string &Other) {
  80. return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0;
  81. };
  82. auto i = endMutableArgs();
  83. auto j = std::find_if(Args.begin(), i, IsMatch);
  84. std::string result;
  85. if (j != i) {
  86. result = j->substr(Arg.length());
  87. }
  88. return result;
  89. }
  90. // Like AddArgument, but adds "-[Flag]=[Value]".
  91. void addFlag(const std::string &Flag, const std::string &Value) {
  92. addArgument("-" + Flag + "=" + Value);
  93. }
  94. // Like RemoveArgument, but removes "-[Flag]=...".
  95. void removeFlag(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. Args.erase(std::remove_if(Args.begin(), i, IsMatch), i);
  102. }
  103. // Returns whether the command's stdout is being written to an output file.
  104. bool hasOutputFile() const { return !OutputFile.empty(); }
  105. // Returns the currently set output file.
  106. const std::string &getOutputFile() const { return OutputFile; }
  107. // Configures the command to redirect its output to the name file.
  108. void setOutputFile(const std::string &FileName) { OutputFile = FileName; }
  109. // Returns whether the command's stderr is redirected to stdout.
  110. bool isOutAndErrCombined() const { return CombinedOutAndErr; }
  111. // Sets whether to redirect the command's stderr to its stdout.
  112. void combineOutAndErr(bool combine = true) { CombinedOutAndErr = combine; }
  113. // Returns a string representation of the command. On many systems this will
  114. // be the equivalent command line.
  115. std::string toString() const {
  116. std::stringstream SS;
  117. for (auto arg : getArguments())
  118. SS << arg << " ";
  119. if (hasOutputFile())
  120. SS << ">" << getOutputFile() << " ";
  121. if (isOutAndErrCombined())
  122. SS << "2>&1 ";
  123. std::string result = SS.str();
  124. if (!result.empty())
  125. result = result.substr(0, result.length() - 1);
  126. return result;
  127. }
  128. private:
  129. Command(Command &&Other) = delete;
  130. Command &operator=(Command &&Other) = delete;
  131. std::vector<std::string>::iterator endMutableArgs() {
  132. return std::find(Args.begin(), Args.end(), ignoreRemainingArgs());
  133. }
  134. std::vector<std::string>::const_iterator endMutableArgs() const {
  135. return std::find(Args.begin(), Args.end(), ignoreRemainingArgs());
  136. }
  137. // The command arguments. Args[0] is the command name.
  138. std::vector<std::string> Args;
  139. // True indicates stderr is redirected to stdout.
  140. bool CombinedOutAndErr;
  141. // If not empty, stdout is redirected to the named file.
  142. std::string OutputFile;
  143. };
  144. } // namespace fuzzer
  145. #endif // LLVM_FUZZER_COMMAND_H