#Centipede Fix interaction between --stop_at / --stop_after / --config / --save_config `--stop_after` used to reset `--stop_at` in its `OnUpdate` handler. This created a usability problem: a command line ``` centipede --stop_after=6h --save_config=centipede.cfg ``` would set both flags in centipede.cfg, not just `--stop_after`. The flags in centipede.cfg are alphabetically sorted, so in a subsequent run: ``` centipede --config=centipede.cfg ``` the value of `--stop_at` would win, resulting in a fixed termination time, possibly in the past. PiperOrigin-RevId: 623236580
diff --git a/centipede/environment_flags.cc b/centipede/environment_flags.cc index 576e579..7e925a8 100644 --- a/centipede/environment_flags.cc +++ b/centipede/environment_flags.cc
@@ -33,7 +33,9 @@ #include "./centipede/logging.h" #include "./centipede/util.h" -static const auto *default_env = new centipede::Environment(); +namespace { +const auto *default_env = new centipede::Environment(); +} // namespace // TODO(kcc): document usage of standalone binaries and how to use @@ wildcard. // If the "binary" contains @@, it means the binary can only accept inputs @@ -160,14 +162,10 @@ "supported. Tip: `date` is useful for conversion of mostly free " "format human readable date/time strings, e.g. " "--stop_at=$(date --date='next Monday 6pm' --utc --iso-8601=seconds) " - ". Also see --stop_after. If both are specified, the last one wins."); + ". Also see --stop_after. These two flags are mutually exclusive."); ABSL_FLAG(absl::Duration, stop_after, absl::InfiniteDuration(), "Equivalent to setting --stop_at to the current date/time + this " - "duration. If both flags are specified, the last one wins.") - .OnUpdate([]() { - absl::SetFlag( // - &FLAGS_stop_at, absl::Now() + absl::GetFlag(FLAGS_stop_after)); - }); + "duration. These two flags are mutually exclusive."); ABSL_FLAG(bool, fork_server, default_env->fork_server, "If true (default) tries to execute the target(s) via the fork " "server, if supported by the target(s). Prepend the binary path with " @@ -356,12 +354,11 @@ ABSL_FLAG(size_t, shmem_size_mb, default_env->shmem_size_mb, "Size of the shared memory regions used to communicate between the " "ending and the runner."); -ABSL_FLAG( - bool, use_posix_shmem, default_env->use_posix_shmem, - "[INTERNAL] When true, uses shm_open/shm_unlink instead of memfd_create to " - "allocate shared memory. You may want this if your target doesn't have " - "access to /proc/<arbitrary_pid> subdirs or the memfd_create syscall is " - "not supported."); +ABSL_FLAG(bool, use_posix_shmem, default_env->use_posix_shmem, + "[INTERNAL] When true, uses shm_open/shm_unlink instead of " + "memfd_create to allocate shared memory. You may want this if your " + "target doesn't have access to /proc/<arbitrary_pid> subdirs or the " + "memfd_create syscall is not supported."); ABSL_FLAG(bool, dry_run, default_env->dry_run, "Initializes as much of Centipede as possible without actually " "running any fuzzing. Useful to validate the rest of the command " @@ -369,9 +366,9 @@ "etc. Also useful in combination with --save_config or " "--update_config to stop execution immediately after writing the " "(updated) config file."); -ABSL_FLAG( - bool, save_binary_info, default_env->save_binary_info, - "Save the BinaryInfo from the fuzzing run within the working directory."); +ABSL_FLAG(bool, save_binary_info, default_env->save_binary_info, + "Save the BinaryInfo from the fuzzing run within the working " + "directory."); ABSL_FLAG(bool, populate_binary_info, default_env->populate_binary_info, "Get binary info from a coverage instrumented binary. This should " "only be turned off when coverage is not based on instrumenting some " @@ -385,6 +382,24 @@ namespace centipede { 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(); + 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(); + } +} + // If the passed `timeout_per_batch` is 0, computes its value as a function of // `timeout_per_input` and `batch_size` and returns it. Otherwise, just returns // the `timeout_per_batch`. @@ -415,6 +430,7 @@ } return timeout_per_batch; } + } // namespace Environment CreateEnvironmentFromFlags(const std::vector<std::string> &argv) { @@ -452,7 +468,8 @@ ComputeTimeoutPerBatch(absl::GetFlag(FLAGS_timeout_per_batch), absl::GetFlag(FLAGS_timeout_per_input), absl::GetFlag(FLAGS_batch_size)), - .stop_at = absl::GetFlag(FLAGS_stop_at), + .stop_at = GetStopAtTime(absl::GetFlag(FLAGS_stop_at), + absl::GetFlag(FLAGS_stop_after)), .fork_server = absl::GetFlag(FLAGS_fork_server), .full_sync = absl::GetFlag(FLAGS_full_sync), .use_corpus_weights = absl::GetFlag(FLAGS_use_corpus_weights),