Support fork server in engine worker, and expose FuzzTestWorkerInitEarly(). This is for supporting migrating runner on top of the engine worker. Previously the runner directly initializes the fork server before creating the watchdog thread. If we want to migrate runner on top of the worker, not only we need to initialize fork server before watchdog, but also do it before the engine worker creating persistent mode socket connection, otherwise the parent process would have the connected socket too and break the invariant needed for persistent mode. PiperOrigin-RevId: 991784397
diff --git a/centipede/BUILD b/centipede/BUILD index 6279af0..6e1f7a1 100644 --- a/centipede/BUILD +++ b/centipede/BUILD
@@ -994,6 +994,7 @@ ":engine_abi", ":execution_metadata", ":feature", + ":runner_fork_server", ":runner_request", ":runner_result", ":runner_utils",
diff --git a/centipede/centipede_test.cc b/centipede/centipede_test.cc index ac1ade9..3c45b83 100644 --- a/centipede/centipede_test.cc +++ b/centipede/centipede_test.cc
@@ -1539,7 +1539,7 @@ "centipede/testing/test_binary_for_engine_testing"); env.test_name = "some_test"; env.populate_binary_info = false; - env.fork_server = false; + env.fork_server = true; env.persistent_mode = true; env.exit_on_crash = true; env.stop_at = absl::Now() + absl::Seconds(10);
diff --git a/centipede/engine_worker.cc b/centipede/engine_worker.cc index 28228b0..a902fa1 100644 --- a/centipede/engine_worker.cc +++ b/centipede/engine_worker.cc
@@ -306,65 +306,7 @@ } // Zero initialized. -static int persistent_mode_socket; - -__attribute__((constructor(200))) void WorkerInitEarly() { - const char* persistent_mode_socket_path = - GetWorkerFlags().GetStringFlag(kWorkerPersistentModeSocketPathFlagHeader); - if (persistent_mode_socket_path == nullptr) return; - persistent_mode_socket = socket(AF_UNIX, SOCK_STREAM, 0); - if (persistent_mode_socket < 0) { - WorkerLog( - "Failed to create persistent mode socket - not running persistent " - "mode.", - LogLnSync{}); - return; - } - - struct sockaddr_un addr{}; - addr.sun_family = AF_UNIX; - const size_t socket_path_len = strlen(persistent_mode_socket_path); - WorkerCheck( - socket_path_len < sizeof(addr.sun_path), - "persistent mode socket path string must be fit in sockaddr_un.sun_path"); - std::memcpy(addr.sun_path, persistent_mode_socket_path, socket_path_len); - - int connect_ret = 0; - do { - connect_ret = - connect(persistent_mode_socket, (struct sockaddr*)&addr, sizeof(addr)); - } while (connect_ret == -1 && errno == EINTR); - if (connect_ret == -1) { - WorkerLog("Failed to connect the persistent mode socket to ", - persistent_mode_socket_path, LogLnSync{}); - (void)close(persistent_mode_socket); - persistent_mode_socket = -1; - return; - } - - int flags = fcntl(persistent_mode_socket, F_GETFD); - if (flags == -1) { - WorkerLog( - "fcntl(F_GETFD) failed on the persistent mode socket - exiting " - "persistent mode", - LogLnSync{}); - (void)close(persistent_mode_socket); - persistent_mode_socket = -1; - return; - } - flags |= FD_CLOEXEC; - if (fcntl(persistent_mode_socket, F_SETFD, flags) == -1) { - WorkerLog( - "fcntl(F_SETFD) failed on the persistent mode socket - exiting " - "persistent mode", - LogLnSync{}); - (void)close(persistent_mode_socket); - persistent_mode_socket = -1; - return; - } - WorkerLog("Persistent mode: connected to ", persistent_mode_socket_path, - LogLnSync{}); -} +int persistent_mode_socket; size_t GetShmemSize() { static auto result = []() -> size_t { @@ -976,6 +918,73 @@ } // namespace +// Defined in the fork server library. +extern void ForkServerCallMeVeryEarly(); + +__attribute__((constructor(200))) void WorkerInitEarly() { + static bool inited = false; + if (inited) return; + inited = true; + + ForkServerCallMeVeryEarly(); + + const char* persistent_mode_socket_path = + GetWorkerFlags().GetStringFlag(kWorkerPersistentModeSocketPathFlagHeader); + if (persistent_mode_socket_path == nullptr) return; + persistent_mode_socket = socket(AF_UNIX, SOCK_STREAM, 0); + if (persistent_mode_socket < 0) { + WorkerLog( + "Failed to create persistent mode socket - not running persistent " + "mode.", + LogLnSync{}); + return; + } + + struct sockaddr_un addr{}; + addr.sun_family = AF_UNIX; + const size_t socket_path_len = strlen(persistent_mode_socket_path); + WorkerCheck( + socket_path_len < sizeof(addr.sun_path), + "persistent mode socket path string must be fit in sockaddr_un.sun_path"); + std::memcpy(addr.sun_path, persistent_mode_socket_path, socket_path_len); + + int connect_ret = 0; + do { + connect_ret = + connect(persistent_mode_socket, (struct sockaddr*)&addr, sizeof(addr)); + } while (connect_ret == -1 && errno == EINTR); + if (connect_ret == -1) { + WorkerLog("Failed to connect the persistent mode socket to ", + persistent_mode_socket_path, LogLnSync{}); + (void)close(persistent_mode_socket); + persistent_mode_socket = -1; + return; + } + + int flags = fcntl(persistent_mode_socket, F_GETFD); + if (flags == -1) { + WorkerLog( + "fcntl(F_GETFD) failed on the persistent mode socket - exiting " + "persistent mode", + LogLnSync{}); + (void)close(persistent_mode_socket); + persistent_mode_socket = -1; + return; + } + flags |= FD_CLOEXEC; + if (fcntl(persistent_mode_socket, F_SETFD, flags) == -1) { + WorkerLog( + "fcntl(F_SETFD) failed on the persistent mode socket - exiting " + "persistent mode", + LogLnSync{}); + (void)close(persistent_mode_socket); + persistent_mode_socket = -1; + return; + } + WorkerLog("Persistent mode: connected to ", persistent_mode_socket_path, + LogLnSync{}); +} + } // namespace fuzztest::internal namespace { @@ -983,10 +992,13 @@ using ::fuzztest::internal::GetWorkerFlags; using ::fuzztest::internal::GetWorkerFlagsEnv; using ::fuzztest::internal::WorkerCheck; +using ::fuzztest::internal::WorkerInitEarly; using ::fuzztest::internal::WorkerRun; } // namespace +void FuzzTestWorkerInitEarly() { WorkerInitEarly(); } + int FuzzTestWorkerIsRequired() { static int result = GetWorkerFlagsEnv() != nullptr && fuzztest::internal::GetWorkerAction().has_value();
diff --git a/centipede/engine_worker_abi.h b/centipede/engine_worker_abi.h index 2a98089..6d79441 100644 --- a/centipede/engine_worker_abi.h +++ b/centipede/engine_worker_abi.h
@@ -28,6 +28,11 @@ extern "C" { #endif +// Initializes the FuzzTest worker runtime early in the process. Only needs to +// be called explicitly before creating threads during early process startup +// when the fork server is used. +void FuzzTestWorkerInitEarly(); + typedef enum { kFuzzTestWorkerSuccess = 0, // Test should finish with a success. kFuzzTestWorkerFailure, // Test should finish with a failure.
diff --git a/centipede/testing/test_binary_for_engine_testing.cc b/centipede/testing/test_binary_for_engine_testing.cc index 071f223..fbc2d5d 100644 --- a/centipede/testing/test_binary_for_engine_testing.cc +++ b/centipede/testing/test_binary_for_engine_testing.cc
@@ -205,8 +205,7 @@ return ControllerRun(&manager, {absl::StrCat("--binary=", argv[0]), "--test_name=some_test", "--populate_binary_info=0", - "--fork_server=0", "--exit_on_crash"}) == - kFuzzTestControllerSuccess + "--exit_on_crash"}) == kFuzzTestControllerSuccess ? EXIT_SUCCESS : EXIT_FAILURE; }
diff --git a/rust/e2e_tests/test_utils.rs b/rust/e2e_tests/test_utils.rs index 16340e4..235e3aa 100644 --- a/rust/e2e_tests/test_utils.rs +++ b/rust/e2e_tests/test_utils.rs
@@ -47,7 +47,7 @@ /// /// Each arg of `args` should be a string that Centipede recognizes containing a flag with a /// possible value, e.g. `--test_name=my_test_name` or `--exit_on_crash`. In addition to `args`, -/// the function will also pass `--populate_binary_info=0`, `--fork_server=0`, +/// the function will also pass `--populate_binary_info=0`. /// `--persistent_mode=0`, and `--env_diff_for_binaries`. pub fn run_centipede_with_args_expect_termination(fixture: &EnvVars, args: &[&str]) -> String { // Disable interference from Bazel environment variables. @@ -69,8 +69,6 @@ ]; let process = Command::new(&fixture.centipede_path) .arg("--populate_binary_info=0") - .arg("--fork_server=0") - .arg("--persistent_mode=0") .arg(format!("--env_diff_for_binaries={}", env_diff.join(","))) .args(args) .output()
diff --git a/rust/src/options.rs b/rust/src/options.rs index 8241557..6e92f60 100644 --- a/rust/src/options.rs +++ b/rust/src/options.rs
@@ -171,7 +171,6 @@ // TODO(the-shank): provide a way to override this. // allow more crashes to be reported when running with FuzzTest (default is 5) add_arg("--max_num_crash_reports=20".to_string())?; - add_arg("--fork_server=false".to_string())?; add_arg(format!("--print_runner_log={}", options.print_subprocess_log))?; @@ -445,7 +444,8 @@ let args_str: Vec<&str> = args._c_strings.iter().map(|s| s.to_str().expect("invalid utf8")).collect(); - // When running indefinitely, --stop_after must be omitted so Centipede runs until interrupted. + // When running indefinitely, --stop_after must be omitted so Centipede runs until + // interrupted. expect_false!(args_str.iter().any(|s| s.starts_with("--stop_after="))); expect_true!(args_str.contains(&"--test_name=my_mod.my_test")); }