Path: blob/main/contrib/llvm-project/compiler-rt/lib/fuzzer/FuzzerCommand.h
35262 views
//===- FuzzerCommand.h - Interface representing a process -------*- C++ -* ===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7// FuzzerCommand represents a command to run in a subprocess. It allows callers8// to manage command line arguments and output and error streams.9//===----------------------------------------------------------------------===//1011#ifndef LLVM_FUZZER_COMMAND_H12#define LLVM_FUZZER_COMMAND_H1314#include "FuzzerDefs.h"15#include "FuzzerIO.h"1617#include <algorithm>18#include <sstream>19#include <string>20#include <vector>21#include <thread>2223namespace fuzzer {2425class Command final {26public:27// This command line flag is used to indicate that the remaining command line28// is immutable, meaning this flag effectively marks the end of the mutable29// argument list.30static inline const char *ignoreRemainingArgs() {31return "-ignore_remaining_args=1";32}3334Command() : CombinedOutAndErr(false) {}3536explicit Command(const std::vector<std::string> &ArgsToAdd)37: Args(ArgsToAdd), CombinedOutAndErr(false) {}3839explicit Command(const Command &Other)40: Args(Other.Args), CombinedOutAndErr(Other.CombinedOutAndErr),41OutputFile(Other.OutputFile) {}4243Command &operator=(const Command &Other) {44Args = Other.Args;45CombinedOutAndErr = Other.CombinedOutAndErr;46OutputFile = Other.OutputFile;47return *this;48}4950~Command() {}5152// Returns true if the given Arg is present in Args. Only checks up to53// "-ignore_remaining_args=1".54bool hasArgument(const std::string &Arg) const {55auto i = endMutableArgs();56return std::find(Args.begin(), i, Arg) != i;57}5859// Gets all of the current command line arguments, **including** those after60// "-ignore-remaining-args=1".61const std::vector<std::string> &getArguments() const { return Args; }6263// Adds the given argument before "-ignore_remaining_args=1", or at the end64// if that flag isn't present.65void addArgument(const std::string &Arg) {66Args.insert(endMutableArgs(), Arg);67}6869// Adds all given arguments before "-ignore_remaining_args=1", or at the end70// if that flag isn't present.71void addArguments(const std::vector<std::string> &ArgsToAdd) {72Args.insert(endMutableArgs(), ArgsToAdd.begin(), ArgsToAdd.end());73}7475// Removes the given argument from the command argument list. Ignores any76// occurrences after "-ignore_remaining_args=1", if present.77void removeArgument(const std::string &Arg) {78auto i = endMutableArgs();79Args.erase(std::remove(Args.begin(), i, Arg), i);80}8182// Like hasArgument, but checks for "-[Flag]=...".83bool hasFlag(const std::string &Flag) const {84std::string Arg("-" + Flag + "=");85auto IsMatch = [&](const std::string &Other) {86return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0;87};88return std::any_of(Args.begin(), endMutableArgs(), IsMatch);89}9091// Returns the value of the first instance of a given flag, or an empty string92// if the flag isn't present. Ignores any occurrences after93// "-ignore_remaining_args=1", if present.94std::string getFlagValue(const std::string &Flag) const {95std::string Arg("-" + Flag + "=");96auto IsMatch = [&](const std::string &Other) {97return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0;98};99auto i = endMutableArgs();100auto j = std::find_if(Args.begin(), i, IsMatch);101std::string result;102if (j != i) {103result = j->substr(Arg.length());104}105return result;106}107108// Like AddArgument, but adds "-[Flag]=[Value]".109void addFlag(const std::string &Flag, const std::string &Value) {110addArgument("-" + Flag + "=" + Value);111}112113// Like RemoveArgument, but removes "-[Flag]=...".114void removeFlag(const std::string &Flag) {115std::string Arg("-" + Flag + "=");116auto IsMatch = [&](const std::string &Other) {117return Arg.compare(0, std::string::npos, Other, 0, Arg.length()) == 0;118};119auto i = endMutableArgs();120Args.erase(std::remove_if(Args.begin(), i, IsMatch), i);121}122123// Returns whether the command's stdout is being written to an output file.124bool hasOutputFile() const { return !OutputFile.empty(); }125126// Returns the currently set output file.127const std::string &getOutputFile() const { return OutputFile; }128129// Configures the command to redirect its output to the name file.130void setOutputFile(const std::string &FileName) { OutputFile = FileName; }131132// Returns whether the command's stderr is redirected to stdout.133bool isOutAndErrCombined() const { return CombinedOutAndErr; }134135// Sets whether to redirect the command's stderr to its stdout.136void combineOutAndErr(bool combine = true) { CombinedOutAndErr = combine; }137138// Returns a string representation of the command. On many systems this will139// be the equivalent command line.140std::string toString() const {141std::stringstream SS;142for (const auto &arg : getArguments())143SS << arg << " ";144if (hasOutputFile())145SS << ">" << getOutputFile() << " ";146if (isOutAndErrCombined())147SS << "2>&1 ";148std::string result = SS.str();149if (!result.empty())150result = result.substr(0, result.length() - 1);151return result;152}153154private:155Command(Command &&Other) = delete;156Command &operator=(Command &&Other) = delete;157158std::vector<std::string>::iterator endMutableArgs() {159return std::find(Args.begin(), Args.end(), ignoreRemainingArgs());160}161162std::vector<std::string>::const_iterator endMutableArgs() const {163return std::find(Args.begin(), Args.end(), ignoreRemainingArgs());164}165166// The command arguments. Args[0] is the command name.167std::vector<std::string> Args;168169// True indicates stderr is redirected to stdout.170bool CombinedOutAndErr;171172// If not empty, stdout is redirected to the named file.173std::string OutputFile;174};175176} // namespace fuzzer177178#endif // LLVM_FUZZER_COMMAND_H179180181