From 304de5772c1891709594e5d01d6dbbc4e12de3ce Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Wed, 16 Apr 2025 16:09:06 -0700 Subject: [PATCH 1/2] [llvm][cas] Implement basic fuzzer --- llvm/tools/llvm-cas-fuzzer/CMakeLists.txt | 9 ++ .../tools/llvm-cas-fuzzer/llvm-cas-fuzzer.cpp | 83 +++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 llvm/tools/llvm-cas-fuzzer/CMakeLists.txt create mode 100644 llvm/tools/llvm-cas-fuzzer/llvm-cas-fuzzer.cpp diff --git a/llvm/tools/llvm-cas-fuzzer/CMakeLists.txt b/llvm/tools/llvm-cas-fuzzer/CMakeLists.txt new file mode 100644 index 0000000000000..635cda4538aa0 --- /dev/null +++ b/llvm/tools/llvm-cas-fuzzer/CMakeLists.txt @@ -0,0 +1,9 @@ +set(LLVM_LINK_COMPONENTS + CAS + FuzzerCLI + FuzzMutate + Support +) +add_llvm_fuzzer(llvm-cas-fuzzer + llvm-cas-fuzzer.cpp + ) diff --git a/llvm/tools/llvm-cas-fuzzer/llvm-cas-fuzzer.cpp b/llvm/tools/llvm-cas-fuzzer/llvm-cas-fuzzer.cpp new file mode 100644 index 0000000000000..99327981006fe --- /dev/null +++ b/llvm/tools/llvm-cas-fuzzer/llvm-cas-fuzzer.cpp @@ -0,0 +1,83 @@ +#include "llvm/CAS/ActionCache.h" +#include "llvm/CAS/BuiltinUnifiedCASDatabases.h" +#include "llvm/CAS/ObjectStore.h" +#include "llvm/Support/ThreadPool.h" + +using namespace llvm; + +extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) { return 0; } + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + static ExitOnError ExitOnErr("llvm-cas-fuzzer: "); + + if (Size == 0) + return 0; + + SmallString<128> Path; + if (sys::fs::createUniqueDirectory("CAS", Path) != std::error_code()) + return 1; + + size_t NumShards = std::max(uint8_t(1), std::min(Data[0], uint8_t(32))); + ++Data; + --Size; + + StringRef GlobalData(reinterpret_cast(Data), Size); + + StdThreadPool ThreadPool(hardware_concurrency()); + + for (size_t I = 0; I != NumShards; ++I) { + ThreadPool.async([&, I] { + auto [CAS, ActionCache] = + ExitOnErr(cas::createOnDiskUnifiedCASDatabases(Path)); + + ExitOnErr(CAS->setSizeLimit(128)); + + StringRef LocalData = + GlobalData.drop_front(std::min(I, GlobalData.size())); + + std::string KeySuffix = std::to_string(I); + + std::string KeyIDStr; + { + cas::ObjectRef DataRef = ExitOnErr(CAS->storeFromString({}, LocalData)); + cas::CASID DataID = CAS->getID(DataRef); + + cas::ObjectRef KeyPrefixRef = + ExitOnErr(CAS->storeFromString({}, "key")); + cas::ObjectRef KeySuffixRef = + ExitOnErr(CAS->storeFromString({}, KeySuffix)); + cas::ObjectRef KeyRef = + ExitOnErr(CAS->storeFromString({KeyPrefixRef, KeySuffixRef}, "_")); + cas::CASID KeyID = CAS->getID(KeyRef); + ExitOnErr(ActionCache->put(KeyID, DataID)); + KeyIDStr = KeyID.toString(); + } + + { + cas::CASID KeyID = ExitOnErr(CAS->parseID(KeyIDStr)); + auto MaybeKeyRef = CAS->getReference(KeyID); + assert(MaybeKeyRef); + cas::ObjectProxy KeyProxy = ExitOnErr(CAS->getProxy(*MaybeKeyRef)); + assert(KeyProxy.getData() == "_"); + assert(KeyProxy.getNumReferences() == 2); + cas::ObjectProxy KeyPrefixProxy = + ExitOnErr(CAS->getProxy(KeyProxy.getReference(0))); + assert(KeyPrefixProxy.getData() == "key"); + cas::ObjectProxy KeySuffixProxy = + ExitOnErr(CAS->getProxy(KeyProxy.getReference(1))); + assert(KeySuffixProxy.getData() == KeySuffix); + + auto MaybeDataID = ExitOnErr(ActionCache->get(KeyID)); + assert(MaybeDataID); + cas::ObjectProxy DataProxy = ExitOnErr(CAS->getProxy(*MaybeDataID)); + assert(DataProxy.getData() == LocalData); + } + + ExitOnErr(CAS->pruneStorageData()); + }); + } + + ThreadPool.wait(); + + return 0; +} From 428de810ab813b431ab5afd452810b166816569f Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Mon, 5 May 2025 11:31:20 -0700 Subject: [PATCH 2/2] Print path, remove on success --- llvm/tools/llvm-cas-fuzzer/llvm-cas-fuzzer.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/llvm/tools/llvm-cas-fuzzer/llvm-cas-fuzzer.cpp b/llvm/tools/llvm-cas-fuzzer/llvm-cas-fuzzer.cpp index 99327981006fe..3b4371252026e 100644 --- a/llvm/tools/llvm-cas-fuzzer/llvm-cas-fuzzer.cpp +++ b/llvm/tools/llvm-cas-fuzzer/llvm-cas-fuzzer.cpp @@ -1,3 +1,4 @@ +#include "llvm/ADT/ScopeExit.h" #include "llvm/CAS/ActionCache.h" #include "llvm/CAS/BuiltinUnifiedCASDatabases.h" #include "llvm/CAS/ObjectStore.h" @@ -17,6 +18,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { if (sys::fs::createUniqueDirectory("CAS", Path) != std::error_code()) return 1; + ExitOnErr.setBanner(("llvm-cas-fuzzer using '" + Path + "':").str()); + size_t NumShards = std::max(uint8_t(1), std::min(Data[0], uint8_t(32))); ++Data; --Size; @@ -79,5 +82,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { ThreadPool.wait(); + sys::fs::remove_directories(Path); + return 0; }