diff --git a/CMakeLists.txt b/CMakeLists.txt index daae8a4..1d8c9f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,6 +37,8 @@ target_compile_definitions(conflict_set_test PRIVATE ENABLE_TESTS) target_compile_options(conflict_set_test PRIVATE -UNDEBUG) # Only emit compile warnings for test target_compile_options(conflict_set_test PRIVATE -Wall -Wextra -Wpedantic -Wunreachable-code) +target_compile_options(conflict_set_test PRIVATE -fsanitize=address,undefined) +target_link_options(conflict_set_test PRIVATE -fsanitize=address,undefined) add_test(NAME conflict_set_test COMMAND conflict_set_test) # api smoke tests diff --git a/ConflictSet.cpp b/ConflictSet.cpp index f285017..67c465c 100644 --- a/ConflictSet.cpp +++ b/ConflictSet.cpp @@ -502,7 +502,9 @@ Node *createNode(const Key &key, Node *parent, int64_t pointVersion, result->priority &= 0xff; #endif result->len = key.len; - memcpy(result + 1, key.p, key.len); + if (key.len > 0) { + memcpy(result + 1, key.p, key.len); + } return result; } @@ -738,7 +740,7 @@ void lastLeqMulti(Arena &arena, Node *root, std::span keys, } [[maybe_unused]] Key toKey(Arena &arena, int n) { - constexpr int kMaxLength = 4; + constexpr int kMaxLength = 8; int i = kMaxLength; uint8_t *itoaBuf = new (arena) uint8_t[kMaxLength]; memset(itoaBuf, '0', kMaxLength); @@ -750,7 +752,7 @@ void lastLeqMulti(Arena &arena, Node *root, std::span keys, } [[maybe_unused]] Key toKeyAfter(Arena &arena, int n) { - constexpr int kMaxLength = 4; + constexpr int kMaxLength = 8; int i = kMaxLength; uint8_t *itoaBuf = new (arena) uint8_t[kMaxLength + 1]; memset(itoaBuf, '0', kMaxLength); @@ -964,7 +966,8 @@ struct __attribute__((__visibility__("hidden"))) ConflictSet::Impl { // We could interleave the iteration in ::next, but we'd need a careful // analysis for correctness and it's unlikely to be worthwhile. auto *prev = ::next(newNode, false); - // The empty key always exists. If *key is empty then we won't reach here. + // The empty key always exists. If key is empty then we won't reach + // here. assert(prev != nullptr); assert(prev->rangeVersion <= writeVersion); newNode->rangeVersion = prev->rangeVersion; @@ -1251,21 +1254,22 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { int numWrites = gArbitrary.bounded(10); int64_t v = ++writeVersion; auto *writes = new (arena) ConflictSet::WriteRange[numWrites]; - std::set, ArenaAlloc> keys{ - ArenaAlloc(&arena)}; + std::set, + ArenaAlloc> + keys{ArenaAlloc(&arena)}; while (int(keys.size()) < numWrites) { if (!gArbitrary.hasEntropy()) { // Tell the fuzzer it's not interesting return -1; } int keyLen = gArbitrary.bounded(8); - auto* begin = new (arena) uint8_t[keyLen]; + auto *begin = new (arena) uint8_t[keyLen]; gArbitrary.randomHex(begin, keyLen); - keys.insert(std::string_view((const char*)begin, keyLen)); + keys.insert(std::string_view((const char *)begin, keyLen)); } auto iter = keys.begin(); for (int i = 0; i < numWrites; ++i) { - writes[i].begin.p = (const uint8_t*)iter->data(); + writes[i].begin.p = (const uint8_t *)iter->data(); writes[i].begin.len = iter->size(); writes[i].end.len = 0; writes[i].writeVersion = v; @@ -1281,21 +1285,22 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { int numReads = gArbitrary.bounded(10); int64_t v = writeVersion - gArbitrary.bounded(10); auto *reads = new (arena) ConflictSet::ReadRange[numReads]; - std::set, ArenaAlloc> keys{ - ArenaAlloc(&arena)}; + std::set, + ArenaAlloc> + keys{ArenaAlloc(&arena)}; while (int(keys.size()) < numReads) { if (!gArbitrary.hasEntropy()) { // Tell the fuzzer it's not interesting return -1; } int keyLen = gArbitrary.bounded(8); - auto* begin = new (arena) uint8_t[keyLen]; + auto *begin = new (arena) uint8_t[keyLen]; gArbitrary.randomHex(begin, keyLen); - keys.insert(std::string_view((const char*)begin, keyLen)); + keys.insert(std::string_view((const char *)begin, keyLen)); } auto iter = keys.begin(); for (int i = 0; i < numReads; ++i) { - reads[i].begin.p = (const uint8_t*)iter->data(); + reads[i].begin.p = (const uint8_t *)iter->data(); reads[i].begin.len = iter->size(); reads[i].end.len = 0; reads[i].readVersion = v;