Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions centipede/binary_info.cc
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,11 @@ void BinaryInfo::InitializeFromSanCovBinary(
std::filesystem::path{tmp_dir_path} / "binary_info_log_tmp";
FUZZTEST_LOG(INFO) << __func__ << ": tmp_dir: " << tmp_dir;

env_diff.push_back(absl::StrCat(
"CENTIPEDE_RUNNER_FLAGS=:dump_binary_info:arg1=", pc_table_path.path(),
":arg2=", cf_table_path.path(), ":arg3=", dso_table_path.path(), ":"));
env_diff.push_back(
absl::StrCat("CENTIPEDE_RUNNER_FLAGS=:dump_binary_info:arg1=",
EscapeEngineFlag(pc_table_path.path()),
":arg2=", EscapeEngineFlag(cf_table_path.path()),
":arg3=", EscapeEngineFlag(dso_table_path.path()), ":"));
Command::Options cmd_options;
cmd_options.env_diff = std::move(env_diff);
cmd_options.stdout_file_prefix = log_prefix;
Expand Down
46 changes: 26 additions & 20 deletions centipede/centipede_callbacks.cc
Original file line number Diff line number Diff line change
Expand Up @@ -360,11 +360,12 @@ std::string CentipedeCallbacks::ConstructRunnerFlags(
if (env_.use_dataflow_features) flags.emplace_back("use_dataflow_features");
}
if (!env_.runner_dl_path_suffix.empty()) {
flags.emplace_back(
absl::StrCat("dl_path_suffix=", env_.runner_dl_path_suffix));
flags.emplace_back(absl::StrCat(
"dl_path_suffix=", EscapeEngineFlag(env_.runner_dl_path_suffix)));
}
if (!env_.pcs_file_path.empty())
flags.emplace_back(absl::StrCat("pcs_file_path=", env_.pcs_file_path));
flags.emplace_back(
absl::StrCat("pcs_file_path=", EscapeEngineFlag(env_.pcs_file_path)));
if (!extra_flags.empty()) flags.emplace_back(extra_flags);
flags.emplace_back("");
return absl::StrJoin(flags, ":");
Expand Down Expand Up @@ -399,15 +400,19 @@ CentipedeCallbacks::GetOrCreateCommandContextForBinary(
}
std::vector<std::string> env_diff = env_.env_diff_for_binaries;
env_diff.push_back(ConstructRunnerFlags(
absl::StrCat(":shmem:test=", env_.test_name, ":arg1=",
inputs_blobseq_.path(), ":arg2=", outputs_blobseq_.path(),
":failure_description_path=", failure_description_path_,
":failure_signature_path=", failure_signature_path_,
persistent_mode_server == nullptr
? ""
: absl::StrCat(":persistent_mode_socket=",
persistent_mode_server->server_path()),
":"),
absl::StrCat(
":shmem:test=", EscapeEngineFlag(env_.test_name),
":arg1=", EscapeEngineFlag(inputs_blobseq_.path()),
":arg2=", EscapeEngineFlag(outputs_blobseq_.path()),
":failure_description_path=",
EscapeEngineFlag(failure_description_path_),
":failure_signature_path=", EscapeEngineFlag(failure_signature_path_),
persistent_mode_server == nullptr
? ""
: absl::StrCat(
":persistent_mode_socket=",
EscapeEngineFlag(persistent_mode_server->server_path())),
":"),
disable_coverage));

if (env_.clang_coverage_binary == binary) {
Expand Down Expand Up @@ -648,12 +653,13 @@ bool CentipedeCallbacks::GetSeedsViaExternalBinary(
FUZZTEST_CHECK(!error) << "Failed to create seed inputs directory "
<< output_dir << ": " << error.message();

std::string centipede_runner_flags = absl::StrCat(
"CENTIPEDE_RUNNER_FLAGS=:dump_seed_inputs:test=", env_.test_name,
":arg1=", output_dir.string(), ":");
std::string centipede_runner_flags =
absl::StrCat("CENTIPEDE_RUNNER_FLAGS=:dump_seed_inputs:test=",
EscapeEngineFlag(env_.test_name),
":arg1=", EscapeEngineFlag(output_dir.string()), ":");
if (!env_.runner_dl_path_suffix.empty()) {
absl::StrAppend(&centipede_runner_flags,
"dl_path_suffix=", env_.runner_dl_path_suffix, ":");
absl::StrAppend(&centipede_runner_flags, "dl_path_suffix=",
EscapeEngineFlag(env_.runner_dl_path_suffix), ":");
}
Command::Options cmd_options;
cmd_options.env_diff = env_.env_diff_for_binaries;
Expand Down Expand Up @@ -716,10 +722,10 @@ bool CentipedeCallbacks::GetSerializedTargetConfigViaExternalBinary(
std::filesystem::path{temp_dir_} / "configuration";
std::string centipede_runner_flags =
absl::StrCat("CENTIPEDE_RUNNER_FLAGS=:dump_configuration:arg1=",
config_file_path.string(), ":");
EscapeEngineFlag(config_file_path.string()), ":");
if (!env_.runner_dl_path_suffix.empty()) {
absl::StrAppend(&centipede_runner_flags,
"dl_path_suffix=", env_.runner_dl_path_suffix, ":");
absl::StrAppend(&centipede_runner_flags, "dl_path_suffix=",
EscapeEngineFlag(env_.runner_dl_path_suffix), ":");
}
Command::Options cmd_options;
cmd_options.env_diff = env_.env_diff_for_binaries;
Expand Down
81 changes: 81 additions & 0 deletions centipede/runner_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string_view>

#include "absl/base/nullability.h"

Expand Down Expand Up @@ -96,4 +98,83 @@ bool WriteAll(int fd, const char* data, size_t size) {
return true;
}

size_t ProcessEngineFlags(char* flags, size_t size) {
size_t r = 0;
size_t w = 0;
size_t cur_flag_beg = 0;
for (r = 0; r < size; ++r) {
if (flags[r] == ':') {
if (w > 0 && w == cur_flag_beg) {
// Skip empty flags
continue;
}
flags[w++] = 0;
cur_flag_beg = w;
continue;
}
// Skip copying if no flag beg was scanned before.
if (cur_flag_beg == 0) continue;
if (flags[r] == '\\' && r + 1 < size) {
++r;
}
flags[w++] = flags[r];
}
if (cur_flag_beg < 2) return 0;
return cur_flag_beg;
}

EngineFlagHelper::EngineFlagHelper(const char* absl_nullable flags)
: flags_(nullptr), size_(0), has_allocation_failure_(false) {
if (flags == nullptr) return;
flags_ = strdup(flags);
if (flags_ == nullptr) {
has_allocation_failure_ = true;
return;
}
size_ = ProcessEngineFlags(flags_, strlen(flags_));
}

EngineFlagHelper::~EngineFlagHelper() {
if (flags_) {
free(flags_);
}
}

bool EngineFlagHelper::HasAllocationFailure() const {
return has_allocation_failure_;
}

bool EngineFlagHelper::HasSwitchFlag(std::string_view flag) const {
return FindEntry(flag, /*match_whole=*/true) != nullptr;
}

uint64_t EngineFlagHelper::GetIntFlag(std::string_view header,
uint64_t default_value) const {
const char* absl_nullable flag = GetStringFlag(header);
if (flag == nullptr) return default_value;
return atoll(flag); // NOLINT: can't use strto64, etc.
}

const char* absl_nullable EngineFlagHelper::GetStringFlag(
std::string_view header) const {
const char* absl_nullable entry = FindEntry(header);
if (entry == nullptr) return nullptr;
return entry + header.size();
}

const char* absl_nullable EngineFlagHelper::FindEntry(std::string_view flag,
bool match_whole) const {
if (flags_ == nullptr || flag.empty()) return nullptr;
auto flags = std::string_view{flags_, size_};
while (true) {
auto match = flags.find(flag);
if (match == flags.npos) return nullptr;
if ((match > 0 && flags[match - 1] == 0) &&
(!match_whole || flags[match + flag.size()] == 0)) {
return flags.data() + match;
}
flags = flags.substr(match + flag.size());
}
}

} // namespace fuzztest::internal
75 changes: 21 additions & 54 deletions centipede/runner_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,73 +129,40 @@ class ExplicitLifetime {
alignas(T) unsigned char space_[sizeof(T)];
};

// Processes the `flags` buffer in-place, which comes with the format of
// :(NAME=VALUE:|NAME:)+, where NAME and VALUE can contain escaped chars with
// backslash (\). It drops any chars before the first colon or after the last
// unescaped colon, drops any empty flags, and replaces unescaped colons with
// '\0'. Returns the number of chars in the processed result.
//
// Returns 0 if no proper flags are found in the `flags` buffer.
size_t ProcessEngineFlags(char* flags, size_t size);

// Helper class for processing and reading the engine flags.
class EngineFlagHelper {
public:
// Constructs the helper for a C-string `flags` with the format of :(ENTRY:)+.
explicit EngineFlagHelper(const char* absl_nullable flags)
: flags_(nullptr), size_(0), has_allocation_failure_(false) {
if (flags == nullptr) return;
flags_ = strdup(flags);
if (flags_ == nullptr) {
has_allocation_failure_ = true;
return;
}
size_ = strlen(flags_);
// Post-processing to make '\0' as the separator, making each item as a
// null-terminating string to be used without copying it.
for (size_t i = 0; i < size_; ++i) {
if (flags_[i] == ':') flags_[i] = 0;
}
}
explicit EngineFlagHelper(const char* absl_nullable flags);

EngineFlagHelper(const EngineFlagHelper&) = delete;
EngineFlagHelper& operator=(const EngineFlagHelper&) = delete;

~EngineFlagHelper() {
if (flags_) {
free(flags_);
}
}
~EngineFlagHelper();

bool HasAllocationFailure() const { return has_allocation_failure_; }

bool HasSwitchFlag(std::string_view name) const {
if (name.empty() || flags_ == nullptr) return false;
const auto flags = std::string_view{flags_, size_};
size_t pos = 0;
while (pos = flags.find(name, pos),
pos != flags.npos && pos + name.size() < flags.size()) {
if (pos > 0 && flags[pos - 1] == '\0' &&
flags[pos + name.size()] == '\0') {
return true;
}
pos += name.size();
}
return false;
}
bool HasAllocationFailure() const;

uint64_t GetIntFlag(std::string_view header, uint64_t default_value) const {
const char* absl_nullable flag = GetStringFlag(header);
if (flag == nullptr) return default_value;
return atoll(flag); // NOLINT: can't use strto64, etc.
}
bool HasSwitchFlag(std::string_view flag) const;

const char* absl_nullable GetStringFlag(std::string_view header) const {
if (header.empty() || flags_ == nullptr) return nullptr;
const auto flags = std::string_view{flags_, size_};
size_t pos = 0;
while (pos = flags.find(header, pos),
pos != flags.npos && pos + header.size() < flags.size()) {
if (pos > 0 && flags[pos - 1] == '\0') {
return flags.data() + pos + header.size();
}
pos += header.size();
}
return nullptr;
}
uint64_t GetIntFlag(std::string_view header, uint64_t default_value) const;

const char* absl_nullable GetStringFlag(std::string_view header) const;

private:
// Returns an entry in the flags for `flag`. If `match_whole` is set, match
// `flag` as the whole entry, otherwise match it as a prefix.
const char* absl_nullable FindEntry(std::string_view flag,
bool match_whole = false) const;

char* absl_nullable flags_;
size_t size_;
bool has_allocation_failure_;
Expand Down
Loading
Loading