[llvm] [CAS] Add llvm-cas-fuzzer for ObjectStore::validate() (PR #190635)

Paul Kirth via llvm-commits llvm-commits at lists.llvm.org
Mon Apr 6 11:31:58 PDT 2026


================
@@ -0,0 +1,388 @@
+//===-- cas-fuzzer.cpp - Fuzzer for CAS ObjectStore::validate() -----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Fuzzer for on-disk CAS validation. Creates a valid CAS database, stores
+// objects, corrupts the on-disk files using fuzzer-provided bytes, then calls
+// validate(). The invariant: validate() must either succeed or return an error,
+// never crash.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/ScopeExit.h"
+#include "llvm/CAS/ActionCache.h"
+#include "llvm/CAS/BuiltinUnifiedCASDatabases.h"
+#include "llvm/CAS/ObjectStore.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdint>
+#include <cstring>
+
+using namespace llvm;
+using namespace llvm::cas;
+
+namespace {
+
+/// Read a little-endian uint32 from Data, or 0 if not enough bytes.
+static uint32_t readU32(const uint8_t *Data, size_t Size, size_t Offset) {
+  if (Offset + 4 > Size)
+    return 0;
+  return support::endian::read32le(Data + Offset);
+}
+
+/// Read a little-endian uint16 from Data, or 0 if not enough bytes.
+static uint16_t readU16(const uint8_t *Data, size_t Size, size_t Offset) {
+  if (Offset + 2 > Size)
+    return 0;
+  return support::endian::read16le(Data + Offset);
+}
+
+/// Find the versioned subdirectory (v1.N) inside the CAS root.
+static std::string findVersionedSubdir(StringRef CASDir) {
+  std::error_code EC;
+  std::string Best;
+  uint64_t BestOrder = 0;
+  for (sys::fs::directory_iterator DirI(CASDir, EC), DirE; !EC && DirI != DirE;
+       DirI.increment(EC)) {
+    if (DirI->type() != sys::fs::file_type::directory_file)
+      continue;
+    StringRef Name = sys::path::filename(DirI->path());
+    if (!Name.starts_with("v1."))
+      continue;
+    uint64_t Order;
+    if (Name.substr(3).getAsInteger(10, Order))
+      continue;
+    if (Best.empty() || Order > BestOrder) {
+      Best = DirI->path();
+      BestOrder = Order;
+    }
+  }
+  return Best;
+}
+
+/// Collect paths of files matching a prefix in a directory.
+static void collectFilesWithPrefix(StringRef Dir, StringRef Prefix,
+                                   SmallVectorImpl<std::string> &Results) {
+  std::error_code EC;
+  for (sys::fs::directory_iterator DirI(Dir, EC), DirE; !EC && DirI != DirE;
+       DirI.increment(EC)) {
+    StringRef Name = sys::path::filename(DirI->path());
+    if (Name.starts_with(Prefix))
+      Results.push_back(DirI->path());
+  }
+}
+
+/// Read an entire file into a buffer.
+static bool readFileBytes(StringRef Path, SmallVectorImpl<char> &Buf) {
+  auto MBOrErr = MemoryBuffer::getFile(Path, /*IsText=*/false,
+                                       /*RequiresNullTerminator=*/false);
+  if (!MBOrErr)
+    return false;
+  Buf.assign((*MBOrErr)->getBufferStart(), (*MBOrErr)->getBufferEnd());
+  return true;
+}
+
+/// Write buffer contents to a file, replacing it entirely.
+static bool writeFileBytes(StringRef Path, ArrayRef<char> Buf) {
+  std::error_code EC;
+  raw_fd_ostream OS(Path, EC, sys::fs::OF_None);
+  if (EC)
+    return false;
+  OS.write(Buf.data(), Buf.size());
+  return !OS.has_error();
+}
+
+/// Create a CAS database and store some baseline objects.
+/// Returns the ObjectRefs for stored objects via LeafRef.
----------------
ilovepi wrote:

This returns `bool`... I'm guessing that the OjectStore gets filled in with this data when you return `true`? 

https://github.com/llvm/llvm-project/pull/190635


More information about the llvm-commits mailing list