179 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			179 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===- FuzzerCommand.h - Interface representing a process -------*- C++ -* ===//
 | |
| //
 | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | |
| // See https://llvm.org/LICENSE.txt for license information.
 | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| // FuzzerCommand represents a command to run in a subprocess.  It allows callers
 | |
| // to manage command line arguments and output and error streams.
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #ifndef LLVM_FUZZER_COMMAND_H
 | |
| #define LLVM_FUZZER_COMMAND_H
 | |
| 
 | |
| #include "FuzzerDefs.h"
 | |
| #include "FuzzerIO.h"
 | |
| 
 | |
| #include <algorithm>
 | |
| #include <sstream>
 | |
| #include <string>
 | |
| #include <vector>
 | |
| 
 | |
| namespace fuzzer {
 | |
| 
 | |
| class Command final {
 | |
| public:
 | |
|   // This command line flag is used to indicate that the remaining command line
 | |
|   // is immutable, meaning this flag effectively marks the end of the mutable
 | |
|   // argument list.
 | |
|   static inline const char *ignoreRemainingArgs() {
 | |
|     return "-ignore_remaining_args=1";
 | |
|   }
 | |
| 
 | |
|   Command() : CombinedOutAndErr(false) {}
 | |
| 
 | |
|   explicit Command(const std::vector<std::string> &ArgsToAdd)
 | |
|       : Args(ArgsToAdd), CombinedOutAndErr(false) {}
 | |
| 
 | |
|   explicit Command(const Command &Other)
 | |
|       : Args(Other.Args), CombinedOutAndErr(Other.CombinedOutAndErr),
 | |
|         OutputFile(Other.OutputFile) {}
 | |
| 
 | |
|   Command &operator=(const Command &Other) {
 | |
|     Args = Other.Args;
 | |
|     CombinedOutAndErr = Other.CombinedOutAndErr;
 | |
|     OutputFile = Other.OutputFile;
 | |
|     return *this;
 | |
|   }
 | |
| 
 | |
|   ~Command() {}
 | |
| 
 | |
|   // Returns true if the given Arg is present in Args.  Only checks up to
 | |
|   // "-ignore_remaining_args=1".
 | |
|   bool hasArgument(const std::string &Arg) const {
 | |
|     auto i = endMutableArgs();
 | |
|     return std::find(Args.begin(), i, Arg) != i;
 | |
|   }
 | |
| 
 | |
|   // Gets all of the current command line arguments, **including** those after
 | |
|   // "-ignore-remaining-args=1".
 | |
|   const std::vector<std::string> &getArguments() const { return Args; }
 | |
| 
 | |
|   // Adds the given argument before "-ignore_remaining_args=1", or at the end
 | |
|   // if that flag isn't present.
 | |
|   void addArgument(const std::string &Arg) {
 | |
|     Args.insert(endMutableArgs(), Arg);
 | |
|   }
 | |
| 
 | |
|   // Adds all given arguments before "-ignore_remaining_args=1", or at the end
 | |
|   // if that flag isn't present.
 | |
|   void addArguments(const std::vector<std::string> &ArgsToAdd) {
 | |
|     Args.insert(endMutableArgs(), ArgsToAdd.begin(), ArgsToAdd.end());
 | |
|   }
 | |
| 
 | |
|   // Removes the given argument from the command argument list.  Ignores any
 | |
|   // occurrences after "-ignore_remaining_args=1", if present.
 | |
|   void removeArgument(const std::string &Arg) {
 | |
|     auto i = endMutableArgs();
 | |
|     Args.erase(std::remove(Args.begin(), i, Arg), i);
 | |
|   }
 | |
| 
 | |
|   // Like hasArgument, but checks for "-[Flag]=...".
 | |
|   bool hasFlag(const std::string &Flag) const {
 | |
|     std::string Arg("-" + Flag + "=");
 | |
|     auto IsMatch = [&](const std::string &Other) {
 | |
|       return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0;
 | |
|     };
 | |
|     return std::any_of(Args.begin(), endMutableArgs(), IsMatch);
 | |
|   }
 | |
| 
 | |
|   // Returns the value of the first instance of a given flag, or an empty string
 | |
|   // if the flag isn't present.  Ignores any occurrences after
 | |
|   // "-ignore_remaining_args=1", if present.
 | |
|   std::string getFlagValue(const std::string &Flag) const {
 | |
|     std::string Arg("-" + Flag + "=");
 | |
|     auto IsMatch = [&](const std::string &Other) {
 | |
|       return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0;
 | |
|     };
 | |
|     auto i = endMutableArgs();
 | |
|     auto j = std::find_if(Args.begin(), i, IsMatch);
 | |
|     std::string result;
 | |
|     if (j != i) {
 | |
|       result = j->substr(Arg.length());
 | |
|     }
 | |
|     return result;
 | |
|   }
 | |
| 
 | |
|   // Like AddArgument, but adds "-[Flag]=[Value]".
 | |
|   void addFlag(const std::string &Flag, const std::string &Value) {
 | |
|     addArgument("-" + Flag + "=" + Value);
 | |
|   }
 | |
| 
 | |
|   // Like RemoveArgument, but removes "-[Flag]=...".
 | |
|   void removeFlag(const std::string &Flag) {
 | |
|     std::string Arg("-" + Flag + "=");
 | |
|     auto IsMatch = [&](const std::string &Other) {
 | |
|       return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0;
 | |
|     };
 | |
|     auto i = endMutableArgs();
 | |
|     Args.erase(std::remove_if(Args.begin(), i, IsMatch), i);
 | |
|   }
 | |
| 
 | |
|   // Returns whether the command's stdout is being written to an output file.
 | |
|   bool hasOutputFile() const { return !OutputFile.empty(); }
 | |
| 
 | |
|   // Returns the currently set output file.
 | |
|   const std::string &getOutputFile() const { return OutputFile; }
 | |
| 
 | |
|   // Configures the command to redirect its output to the name file.
 | |
|   void setOutputFile(const std::string &FileName) { OutputFile = FileName; }
 | |
| 
 | |
|   // Returns whether the command's stderr is redirected to stdout.
 | |
|   bool isOutAndErrCombined() const { return CombinedOutAndErr; }
 | |
| 
 | |
|   // Sets whether to redirect the command's stderr to its stdout.
 | |
|   void combineOutAndErr(bool combine = true) { CombinedOutAndErr = combine; }
 | |
| 
 | |
|   // Returns a string representation of the command.  On many systems this will
 | |
|   // be the equivalent command line.
 | |
|   std::string toString() const {
 | |
|     std::stringstream SS;
 | |
|     for (auto arg : getArguments())
 | |
|       SS << arg << " ";
 | |
|     if (hasOutputFile())
 | |
|       SS << ">" << getOutputFile() << " ";
 | |
|     if (isOutAndErrCombined())
 | |
|       SS << "2>&1 ";
 | |
|     std::string result = SS.str();
 | |
|     if (!result.empty())
 | |
|       result = result.substr(0, result.length() - 1);
 | |
|     return result;
 | |
|   }
 | |
| 
 | |
| private:
 | |
|   Command(Command &&Other) = delete;
 | |
|   Command &operator=(Command &&Other) = delete;
 | |
| 
 | |
|   std::vector<std::string>::iterator endMutableArgs() {
 | |
|     return std::find(Args.begin(), Args.end(), ignoreRemainingArgs());
 | |
|   }
 | |
| 
 | |
|   std::vector<std::string>::const_iterator endMutableArgs() const {
 | |
|     return std::find(Args.begin(), Args.end(), ignoreRemainingArgs());
 | |
|   }
 | |
| 
 | |
|   // The command arguments.  Args[0] is the command name.
 | |
|   std::vector<std::string> Args;
 | |
| 
 | |
|   // True indicates stderr is redirected to stdout.
 | |
|   bool CombinedOutAndErr;
 | |
| 
 | |
|   // If not empty, stdout is redirected to the named file.
 | |
|   std::string OutputFile;
 | |
| };
 | |
| 
 | |
| } // namespace fuzzer
 | |
| 
 | |
| #endif // LLVM_FUZZER_COMMAND_H
 |