From 1e1f5d6d5c9c3bc9aa19cabb4c47f7ee1bd7d33a Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Thu, 16 May 2024 17:29:02 -0700 Subject: [PATCH] Add FacadeFuzz --- CMakeLists.txt | 6 +++ FacadeFuzz.cpp | 107 +++++++++++++++++++++++++++++++++++++++++++++++ KeyCompare.h | 18 ++++++++ VersionedMap.cpp | 12 +----- 4 files changed, 132 insertions(+), 11 deletions(-) create mode 100644 FacadeFuzz.cpp create mode 100644 KeyCompare.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 6828322..304f6eb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -156,6 +156,12 @@ if(BUILD_TESTING) ${TEST_FLAGS}) target_link_options(facade_test PRIVATE -fsanitize=address,undefined) + add_executable(facade_fuzz FacadeFuzz.cpp) + target_link_libraries(facade_fuzz PRIVATE ${PROJECT_NAME}) + target_compile_options(facade_fuzz PRIVATE -fsanitize=address,undefined,fuzzer + ${TEST_FLAGS}) + target_link_options(facade_fuzz PRIVATE -fsanitize=address,undefined,fuzzer) + # symbol visibility tests if(NOT CMAKE_BUILD_TYPE STREQUAL Debug) if(APPLE) diff --git a/FacadeFuzz.cpp b/FacadeFuzz.cpp new file mode 100644 index 0000000..e985f6c --- /dev/null +++ b/FacadeFuzz.cpp @@ -0,0 +1,107 @@ +#include "Facade.h" +#include "Internal.h" +#include "KeyCompare.h" + +#include +#include + +#define DEBUG 0 + +constexpr int kKeySize = 4; + +weaselab::VersionedMap::Key randomKey(Arena &arena) { + auto *result = new (arena) uint8_t[kKeySize]; + gRandom.randomHex(result, kKeySize); + return {result, kKeySize}; +} + +weaselab::VersionedMap::Key arbitraryKey(Arena &arena) { + auto *result = new (arena) uint8_t[kKeySize]; + gArbitrary.randomHex(result, kKeySize); + return {result, kKeySize}; +} + +struct KeyComp { + bool operator()(const weaselab::VersionedMap::Key &lhs, + const weaselab::VersionedMap::Key &rhs) const { + return lhs < rhs; + } +}; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + initFuzz(data, size); + + Facade facade{0}; + Arena arena; + + while (gArbitrary.hasEntropy()) { + switch (gArbitrary.bounded(3)) { + case 0: { + // Add mutations + + const int numKeys = gArbitrary.bounded(10); + std::set keySet; + while (int(keySet.size()) < numKeys) { + keySet.insert(randomKey(arena)); + } + std::vector keys; + keys.insert(keys.end(), keySet.begin(), keySet.end()); + std::vector mutations; + for (int i = 0; i < int(keys.size());) { + switch (gArbitrary.bounded(3)) { + case 0: { + // Point write + auto val = randomKey(arena); + mutations.push_back({keys[i].p, val.p, keys[i].len, val.len, + weaselab::VersionedMap::Set}); + ++i; + } break; + case 1: { + // Point clear + mutations.push_back({keys[i].p, nullptr, keys[i].len, 0, + weaselab::VersionedMap::Clear}); + ++i; + } break; + case 2: { + // Range clear + if (i + 1 < int(keys.size())) { + mutations.push_back({keys[i].p, keys[i + 1].p, keys[i].len, + keys[i + 1].len, + weaselab::VersionedMap::Clear}); + i += 2; + } + } break; + } + } + + facade.addMutations(mutations.data(), mutations.size(), + facade.getVersion() + 1); + + } break; + case 1: { + // Set oldest version + + facade.setOldestVersion(facade.getOldestVersion() + + gArbitrary.bounded(facade.getVersion() - + facade.getOldestVersion() + + 1)); + } break; + case 2: { + // Check range read + + const int64_t version = facade.getOldestVersion() + + gArbitrary.bounded(facade.getVersion() - + facade.getOldestVersion() + 1); + auto begin = arbitraryKey(arena); + auto end = arbitraryKey(arena); + const int limit = gArbitrary.bounded(100000); + const bool reverse = gArbitrary.bounded(2); + + facade.viewAt(version).rangeRead(String(begin.p, begin.len), + String(end.p, end.len), limit, reverse); + } break; + } + } + + return 0; +} \ No newline at end of file diff --git a/KeyCompare.h b/KeyCompare.h new file mode 100644 index 0000000..74478ba --- /dev/null +++ b/KeyCompare.h @@ -0,0 +1,18 @@ +#pragma once + +#include "VersionedMap.h" + +#include +#include + +inline auto operator<=>(const weaselab::VersionedMap::Key &lhs, + const weaselab::VersionedMap::Key &rhs) { + int cl = std::min(lhs.len, rhs.len); + if (cl > 0) { + int c = memcmp(lhs.p, rhs.p, cl); + if (c != 0) { + return c <=> 0; + } + } + return lhs.len <=> rhs.len; +} diff --git a/VersionedMap.cpp b/VersionedMap.cpp index b88fb89..9dfe71e 100644 --- a/VersionedMap.cpp +++ b/VersionedMap.cpp @@ -1,5 +1,6 @@ #include "VersionedMap.h" #include "Internal.h" +#include "KeyCompare.h" #include "RootSet.h" #include @@ -390,17 +391,6 @@ auto operator<=>(const VersionedMap::Key &lhs, const Node &rhs) { return lhs.len <=> rhs.entry->keyLen; } -auto operator<=>(const VersionedMap::Key &lhs, const VersionedMap::Key &rhs) { - int cl = std::min(lhs.len, rhs.len); - if (cl > 0) { - int c = memcmp(lhs.p, rhs.p, cl); - if (c != 0) { - return c <=> 0; - } - } - return lhs.len <=> rhs.len; -} - constexpr int orderToInt(std::strong_ordering o) { return o == std::strong_ordering::less ? -1 : o == std::strong_ordering::equal ? 0