blob: 8db3381dcbb1befeba35c94b66b5380970b93c03 [file] [log] [blame]
// Copyright 2023 The Centipede Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "./centipede/environment_flags.h"
#include <cstdlib>
#include <filesystem> // NOLINT
#include <string>
#include <vector>
#include "absl/flags/flag.h"
#include "absl/strings/match.h"
#include "absl/strings/str_split.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
#include "./centipede/environment.h"
#include "./common/logging.h"
using ::fuzztest::internal::Environment;
#define CENTIPEDE_FLAG(TYPE, NAME, DEFAULT, DESC) \
ABSL_FLAG(TYPE, NAME, DEFAULT, DESC);
#include "./centipede/centipede_flags.inc"
#undef CENTIPEDE_FLAG
#define CENTIPEDE_FLAG_ALIAS(ALIAS_NAME, ORIGINAL_NAME) \
ABSL_FLAG(decltype(Environment::Default().ORIGINAL_NAME), ALIAS_NAME, \
Environment::Default().ORIGINAL_NAME, \
"Alias of --" #ORIGINAL_NAME) \
.OnUpdate([]() { \
absl::SetFlag(&FLAGS_##ORIGINAL_NAME, \
absl::GetFlag(FLAGS_##ALIAS_NAME)); \
});
CENTIPEDE_FLAG_ALIAS(first_shard_index, my_shard_index)
CENTIPEDE_FLAG_ALIAS(timeout, timeout_per_input)
CENTIPEDE_FLAG_ALIAS(num_crash_reports, max_num_crash_reports)
CENTIPEDE_FLAG_ALIAS(minimize_crash, minimize_crash_file_path)
#undef CENTIPEDE_FLAG_ALIAS
ABSL_FLAG(absl::Duration, stop_after, absl::InfiniteDuration(),
"Equivalent to setting --stop_at to the current date/time + this "
"duration. These two flags are mutually exclusive.");
ABSL_RETIRED_FLAG(size_t, distill_shards, 0,
"No longer supported: use --distill instead.");
namespace fuzztest::internal {
namespace {
// Computes the final stop-at time based on the possibly user-provided inputs.
absl::Time GetStopAtTime(absl::Time stop_at, absl::Duration stop_after) {
const bool stop_at_is_non_default = stop_at != absl::InfiniteFuture();
const bool stop_after_is_non_default = stop_after != absl::InfiniteDuration();
FUZZTEST_CHECK_LE(stop_at_is_non_default + stop_after_is_non_default, 1)
<< "At most one of --stop_at and --stop_after should be specified, "
"including via --config file: "
<< VV(stop_at) << VV(stop_after);
if (stop_at_is_non_default) {
return stop_at;
} else if (stop_after_is_non_default) {
return absl::Now() + stop_after;
} else {
return absl::InfiniteFuture();
}
}
} // namespace
Environment CreateEnvironmentFromFlags(const std::vector<std::string> &argv) {
Environment env_from_flags = {
#define CENTIPEDE_FLAG(_TYPE, NAME, _DEFAULT, _DESC) \
absl::GetFlag(FLAGS_##NAME),
#include "./centipede/centipede_flags.inc"
#undef CENTIPEDE_FLAG
};
env_from_flags.stop_at =
GetStopAtTime(env_from_flags.stop_at, absl::GetFlag(FLAGS_stop_after));
if (env_from_flags.coverage_binary.empty()) {
env_from_flags.coverage_binary =
*absl::StrSplit(env_from_flags.binary, ' ').begin();
}
env_from_flags.binary_name =
std::filesystem::path(env_from_flags.coverage_binary).filename().string();
env_from_flags.UpdateBinaryHashIfEmpty();
env_from_flags.UpdateTimeoutPerBatchIfEqualTo(
Environment::Default().timeout_per_batch);
if (size_t j = absl::GetFlag(FLAGS_j)) {
env_from_flags.total_shards = j;
env_from_flags.num_threads = j;
env_from_flags.my_shard_index = 0;
}
FUZZTEST_CHECK_GE(env_from_flags.total_shards, 1);
FUZZTEST_CHECK_GE(env_from_flags.batch_size, 1);
FUZZTEST_CHECK_GE(env_from_flags.num_threads, 1);
FUZZTEST_CHECK_LE(env_from_flags.num_threads, env_from_flags.total_shards);
FUZZTEST_CHECK_LE(env_from_flags.my_shard_index + env_from_flags.num_threads,
env_from_flags.total_shards)
<< VV(env_from_flags.my_shard_index) << VV(env_from_flags.num_threads);
if (!argv.empty()) {
env_from_flags.exec_name = argv[0];
for (size_t i = 1; i < argv.size(); ++i) {
env_from_flags.args.emplace_back(argv[i]);
}
}
if (!env_from_flags.clang_coverage_binary.empty())
env_from_flags.extra_binaries.push_back(
env_from_flags.clang_coverage_binary);
if (absl::StrContains(env_from_flags.binary, "@@")) {
FUZZTEST_LOG(INFO)
<< "@@ detected; running in standalone mode with batch_size=1";
env_from_flags.has_input_wildcards = true;
env_from_flags.batch_size = 1;
// TODO(kcc): do we need to check if extra_binaries have @@?
}
env_from_flags.ReadKnobsFileIfSpecified();
return env_from_flags;
}
} // namespace fuzztest::internal