From 685fae1b386a594cd43add2750ee539745d03875 Mon Sep 17 00:00:00 2001 From: Xinhao Yuan Date: Wed, 12 Aug 2026 15:18:13 -0700 Subject: [PATCH] Pass shmem size explicitly instead querying. Querying the size can be hard on some platforms. This replaces the switch flag :shmem: with the size flag :shmem_size_mb=: PiperOrigin-RevId: 963688253 --- centipede/centipede_callbacks.cc | 5 ++-- centipede/engine_worker.cc | 25 ++++++++++++++++--- centipede/minimize_crash.cc | 2 ++ centipede/runner.cc | 19 ++++++++------ centipede/sancov_state.h | 2 ++ centipede/shared_memory_blob_sequence.cc | 8 +++--- centipede/shared_memory_blob_sequence.h | 6 ++--- centipede/shared_memory_blob_sequence_test.cc | 6 ++--- 8 files changed, 49 insertions(+), 24 deletions(-) diff --git a/centipede/centipede_callbacks.cc b/centipede/centipede_callbacks.cc index 961e93535..6a3afa52b 100644 --- a/centipede/centipede_callbacks.cc +++ b/centipede/centipede_callbacks.cc @@ -399,8 +399,9 @@ CentipedeCallbacks::GetOrCreateCommandContextForBinary( } std::vector 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(), + absl::StrCat(":shmem_size_mb=", env_.shmem_size_mb, + ":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 diff --git a/centipede/engine_worker.cc b/centipede/engine_worker.cc index 3c95801fd..2bba71b4d 100644 --- a/centipede/engine_worker.cc +++ b/centipede/engine_worker.cc @@ -241,6 +241,7 @@ constexpr std::string_view kWorkerPersistentModeSocketPathFlagHeader = "persistent_mode_socket="; // TODO: Use better flag names when // standardizing the protocol. constexpr std::string_view kWorkerCrossOverLevel = "crossover_level="; +constexpr std::string_view kWorkerShmemSizeMbFlagHeader = "shmem_size_mb="; struct WorkerState { std::atomic has_failure_output = false; @@ -407,28 +408,44 @@ __attribute__((constructor(200))) void WorkerInitEarly() { LogLnSync{}); } +size_t GetShmemSize() { + static auto result = []() -> size_t { + const char* shmem_size_mb_str = GetWorkerFlag(kWorkerShmemSizeMbFlagHeader); + if (shmem_size_mb_str != nullptr) { + const int parsed = + atoi(shmem_size_mb_str); // NOLINT: can't use strto64, etc. + if (parsed < 0) return 0; + return static_cast(parsed) << 20; + } + return 0; + }(); + return result; +} + BlobSequence* GetInputsBlobSequence() { static auto result = []() -> BlobSequence* { - if (!HasWorkerSwitchFlag("shmem")) { + const size_t shmem_size = GetShmemSize(); + if (shmem_size == 0) { return nullptr; } const char* input_path = GetWorkerFlag(kWorkerInputsBlobSequencePathFlagHeader); WorkerCheck(input_path != nullptr, "inputs blob sequence is missing"); - return new SharedMemoryBlobSequence(input_path); + return new SharedMemoryBlobSequence(input_path, shmem_size); }(); return result; } BlobSequence* GetOutputsBlobSequence() { static auto result = []() -> BlobSequence* { - if (!HasWorkerSwitchFlag("shmem")) { + const size_t shmem_size = GetShmemSize(); + if (shmem_size == 0) { return nullptr; } const char* output_path = GetWorkerFlag(kWorkerOutputsBlobSequencePathFlagHeader); WorkerCheck(output_path != nullptr, "outputs blob sequence is missing"); - return new SharedMemoryBlobSequence(output_path); + return new SharedMemoryBlobSequence(output_path, shmem_size); }(); return result; } diff --git a/centipede/minimize_crash.cc b/centipede/minimize_crash.cc index 0e1238269..4399dcb0b 100644 --- a/centipede/minimize_crash.cc +++ b/centipede/minimize_crash.cc @@ -143,6 +143,7 @@ void MinimizeCrash(ByteSpan crashy_input, const Environment& env, auto callbacks = scoped_callback.callbacks(); FUZZTEST_LOG(INFO) << "MinimizeCrash: trying the original crashy input"; + CreateLocalDirRemovedAtExit(TemporaryLocalDirPath()); BatchResult batch_result; ByteArray original_crashy_input(crashy_input.begin(), crashy_input.end()); @@ -163,6 +164,7 @@ void MinimizeCrash(ByteSpan crashy_input, const Environment& env, ThreadPool threads{static_cast(env.num_threads)}; for (size_t i = 0; i < env.num_threads; ++i) { threads.Schedule([&env, &callbacks_factory, &queue, &stop_condition]() { + CreateLocalDirRemovedAtExit(TemporaryLocalDirPath()); MinimizeCrash(env, callbacks_factory, queue, stop_condition); }); } diff --git a/centipede/runner.cc b/centipede/runner.cc index 40e4f39bf..3715b8660 100644 --- a/centipede/runner.cc +++ b/centipede/runner.cc @@ -902,9 +902,10 @@ void GlobalRunnerState::OnTermination() { // This means, the binary is standalone with its own main(), and we need to // report the coverage now. if (!state->centipede_runner_main_executed && - flag_helper.HasFlag(":shmem:")) { + sancov_state->shmem_size_mb != 0) { PostProcessSancov(); // TODO(xinhaoyuan): do we know our exit status? - SharedMemoryBlobSequence outputs_blobseq(sancov_state->arg2); + SharedMemoryBlobSequence outputs_blobseq(sancov_state->arg2, + sancov_state->shmem_size_mb << 20); StartSendingOutputsToEngine(outputs_blobseq); FinishSendingOutputsToEngine(outputs_blobseq); } @@ -987,9 +988,9 @@ static int HandlePersistentMode(RunnerCallbacks& callbacks, return EXIT_SUCCESS; } -// If HasFlag(:shmem:), state->arg1 and state->arg2 are the names -// of in/out shared memory locations. -// Read inputs and write outputs via shared memory. +// If sancov_state->shmem_size_mb is non-zero, state->arg1 and state->arg2 are +// the names of in/out shared memory locations. +// Read inputs and write outputs via shared memory. // // Default: Execute ReadOneInputExecuteItAndDumpCoverage() for all inputs.// // @@ -1013,10 +1014,12 @@ int RunnerMain(int argc, char** argv, RunnerCallbacks& callbacks) { } // Inputs / outputs from shmem. - if (state->flag_helper.HasFlag(":shmem:")) { + if (sancov_state->shmem_size_mb != 0) { if (!sancov_state->arg1 || !sancov_state->arg2) return EXIT_FAILURE; - SharedMemoryBlobSequence inputs_blobseq(sancov_state->arg1); - SharedMemoryBlobSequence outputs_blobseq(sancov_state->arg2); + SharedMemoryBlobSequence inputs_blobseq(sancov_state->arg1, + sancov_state->shmem_size_mb << 20); + SharedMemoryBlobSequence outputs_blobseq(sancov_state->arg2, + sancov_state->shmem_size_mb << 20); // Persistent mode loop. if (state->persistent_mode_socket > 0) { return HandlePersistentMode(callbacks, inputs_blobseq, outputs_blobseq); diff --git a/centipede/sancov_state.h b/centipede/sancov_state.h index bde30e12f..e81004132 100644 --- a/centipede/sancov_state.h +++ b/centipede/sancov_state.h @@ -157,6 +157,8 @@ struct SancovState { const char *arg1 = flag_helper.GetStringFlag(":arg1="); const char *arg2 = flag_helper.GetStringFlag(":arg2="); const char *arg3 = flag_helper.GetStringFlag(":arg3="); + const size_t shmem_size_mb = + static_cast(flag_helper.HasIntFlag(":shmem_size_mb=", 0)); SancovFlags flags = { /*path_level=*/std::min(ThreadLocalSancovState::kBoundedPathLength, diff --git a/centipede/shared_memory_blob_sequence.cc b/centipede/shared_memory_blob_sequence.cc index 3a2412649..51415df13 100644 --- a/centipede/shared_memory_blob_sequence.cc +++ b/centipede/shared_memory_blob_sequence.cc @@ -135,7 +135,10 @@ SharedMemoryBlobSequence::SharedMemoryBlobSequence(const char *name, MmapData(); } -SharedMemoryBlobSequence::SharedMemoryBlobSequence(const char *path) { +SharedMemoryBlobSequence::SharedMemoryBlobSequence(const char* path, + size_t size) { + ErrorOnFailure(size < sizeof(Blob::size), "Size too small"); + size_ = size; // This is a quick way to tell shm-allocated paths from memfd paths without // requiring the caller to specify. if (strncmp(path, "/proc/", 6) == 0) { @@ -146,9 +149,6 @@ SharedMemoryBlobSequence::SharedMemoryBlobSequence(const char *path) { ErrorOnFailure(fd_ < 0, "open() failed"); strncpy(path_, path, PATH_MAX); ErrorOnFailure(path_[PATH_MAX - 1] != 0, "path length exceeds PATH_MAX."); - struct stat statbuf = {}; - ErrorOnFailure(fstat(fd_, &statbuf), "fstat() failed"); - size_ = statbuf.st_size; MmapData(); } diff --git a/centipede/shared_memory_blob_sequence.h b/centipede/shared_memory_blob_sequence.h index fc69c10dd..b5d781e3c 100644 --- a/centipede/shared_memory_blob_sequence.h +++ b/centipede/shared_memory_blob_sequence.h @@ -134,7 +134,7 @@ class BlobSequence { // // void Child() { // // Open an existing blob sequence. -// SharedMemoryBlobSequence child("/foo"); +// SharedMemoryBlobSequence child("/foo", 1000); // // // Read the data written by parent. // while (true) { @@ -155,9 +155,9 @@ class SharedMemoryBlobSequence : public BlobSequence { // memfd_create(2). SharedMemoryBlobSequence(const char *name, size_t size, bool use_posix_shmem); - // Opens an existing shared blob sequence with the file `path`. + // Opens an existing shared blob sequence with the file `path` and `size`. // Aborts on any failure. - explicit SharedMemoryBlobSequence(const char *path); + SharedMemoryBlobSequence(const char* path, size_t size); // Releases all resources. ~SharedMemoryBlobSequence(); diff --git a/centipede/shared_memory_blob_sequence_test.cc b/centipede/shared_memory_blob_sequence_test.cc index 2b9f55799..f5dd4fc45 100644 --- a/centipede/shared_memory_blob_sequence_test.cc +++ b/centipede/shared_memory_blob_sequence_test.cc @@ -112,7 +112,7 @@ TEST_P(SharedMemoryBlobSequenceTest, ParentChild) { EXPECT_TRUE(parent.Write(BlobFromVec(kTestData2, 456))); // Child created. - SharedMemoryBlobSequence child(parent.path()); + SharedMemoryBlobSequence child(parent.path(), 1000); // Child reads data. auto blob1 = child.Read(); EXPECT_EQ(kTestData1, Vec(blob1)); @@ -141,14 +141,14 @@ TEST_P(SharedMemoryBlobSequenceTest, CheckForResourceLeaks) { for (int iter = 0; iter < kNumIters; iter++) { SharedMemoryBlobSequence parent(ShmemName().c_str(), kBlobSize, GetParam()); parent.Write(BlobFromVec({1, 2, 3})); - SharedMemoryBlobSequence child(parent.path()); + SharedMemoryBlobSequence child(parent.path(), kBlobSize); EXPECT_EQ(child.Read().size, 3); } // Create a parent blob, then create and destroy lots of child blobs. SharedMemoryBlobSequence parent(ShmemName().c_str(), kBlobSize, GetParam()); parent.Write(BlobFromVec({1, 2, 3, 4})); for (int iter = 0; iter < kNumIters; iter++) { - SharedMemoryBlobSequence child(parent.path()); + SharedMemoryBlobSequence child(parent.path(), kBlobSize); EXPECT_EQ(child.Read().size, 4); } }