diff --git a/Facade.h b/Facade.h index 459b53a..b13b8e1 100644 --- a/Facade.h +++ b/Facade.h @@ -138,11 +138,15 @@ struct Facade { String(m.param2, m.param2Len); break; case weaselab::VersionedMap::Clear: - for (auto unversionedIter = - unversioned.lower_bound(String(m.param1, m.param1Len)); - unversionedIter != unversioned.end() && - unversionedIter->first < String(m.param2, m.param2Len);) { - unversionedIter = unversioned.erase(unversionedIter); + if (m.param2Len == 0) { + unversioned.erase(String(m.param1, m.param1Len)); + } else { + for (auto unversionedIter = + unversioned.lower_bound(String(m.param1, m.param1Len)); + unversionedIter != unversioned.end() && + unversionedIter->first < String(m.param2, m.param2Len);) { + unversionedIter = unversioned.erase(unversionedIter); + } } break; } diff --git a/FacadeFuzz.cpp b/FacadeFuzz.cpp index e985f6c..f772a18 100644 --- a/FacadeFuzz.cpp +++ b/FacadeFuzz.cpp @@ -2,6 +2,7 @@ #include "Internal.h" #include "KeyCompare.h" +#include #include #include @@ -81,10 +82,13 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { case 1: { // Set oldest version - facade.setOldestVersion(facade.getOldestVersion() + - gArbitrary.bounded(facade.getVersion() - - facade.getOldestVersion() + - 1)); + const int64_t newOldestVersion = + facade.getOldestVersion() + + gArbitrary.bounded(facade.getVersion() - facade.getOldestVersion() + + 1); + + facade.setOldestVersion(newOldestVersion); + } break; case 2: { // Check range read diff --git a/RootSet.cpp b/RootSet.cpp index 8012d94..f8374a0 100644 --- a/RootSet.cpp +++ b/RootSet.cpp @@ -123,6 +123,11 @@ struct RootSet::Impl { firstToFree = firstToFree->next; safe_free(tmp, ThreadSafeHandle::Impl::sizeForCapacity(tmp->capacity)); } +#ifndef NDEBUG + assert(rootCount() > 0); + auto *h = handle.load(std::memory_order_relaxed); + assert(h->versions()[h->lastLeq(oldestVersion)] <= oldestVersion); +#endif } const uint32_t *roots() const { diff --git a/VersionedMap.cpp b/VersionedMap.cpp index 9dfe71e..68b5692 100644 --- a/VersionedMap.cpp +++ b/VersionedMap.cpp @@ -262,62 +262,49 @@ struct MemManager { } void gc(const uint32_t *roots, int numRoots, int64_t oldestVersion) { -#if DEBUG_VERBOSE - if (debugVerboseEnabled) { - printf("GC roots:\n"); - for (int i = 0; i < numRoots; ++i) { - printf(" %u\n", roots[i]); - } - } -#endif // Calculate reachable set BitSet reachable{next}; // Each node has at most 3 children and nodes along the search path aren't // in the stack, so we need 2 * kPathLengthUpperBound uint32_t stack[2 * kPathLengthUpperBound]; int stackIndex = 0; - auto tryPush = [&](uint32_t p) { -#if DEBUG_VERBOSE - if (debugVerboseEnabled) { - printf(" GC: visit: %u\n", p); - } -#endif - if (!reachable.set(p)) { + auto tryPush = [&](uint32_t parent, uint32_t child) { + if (!reachable.set(child)) { #if DEBUG_VERBOSE if (debugVerboseEnabled) { - printf(" GC: push on to stack: %u\n", p); + printf(" GC: reach: %u (parent %u)\n", child, parent); } #endif assert(stackIndex < sizeof(stack) / sizeof(stack[0])); - stack[stackIndex++] = p; + stack[stackIndex++] = child; } }; for (int i = 0; i < numRoots; ++i) { if (roots[i] == 0) { continue; } - tryPush(roots[i]); + tryPush(0, roots[i]); while (stackIndex > 0) { uint32_t p = stack[--stackIndex]; auto &node = base[p]; if (node.updated.load(std::memory_order_relaxed)) { if (node.pointer[!node.replacedPointer] != 0) { - tryPush(node.pointer[!node.replacedPointer]); + tryPush(p, node.pointer[!node.replacedPointer]); } if (oldestVersion < node.updateVersion) { if (node.pointer[node.replacedPointer] != 0) { - tryPush(node.pointer[node.replacedPointer]); + tryPush(p, node.pointer[node.replacedPointer]); } } if (node.pointer[2] != 0) { - tryPush(node.pointer[2]); + tryPush(p, node.pointer[2]); } } else { if (node.pointer[0] != 0) { - tryPush(node.pointer[0]); + tryPush(p, node.pointer[0]); } if (node.pointer[1] != 0) { - tryPush(node.pointer[1]); + tryPush(p, node.pointer[1]); } } } @@ -495,6 +482,11 @@ struct __attribute__((__visibility__("hidden"))) VersionedMap::Impl { result = n.pointer[which]; } assert(result == 0 || result >= kMinAddressable); +#ifndef NDEBUG + if (result != 0) { + assert(mm.base[result].entry != nullptr); + } +#endif return result; } @@ -1174,6 +1166,7 @@ void VersionedMap::firstGeq(const Key *key, const int64_t *version, VersionedMap::Iterator VersionedMap::begin(int64_t version) const { VersionedMap::Iterator result; result.impl = new (safe_malloc(sizeof(Iterator::Impl))) Iterator::Impl(); + result.impl->version = version; bool ignored; result.impl->finger.push( @@ -1205,7 +1198,6 @@ VersionedMap::Iterator VersionedMap::begin(int64_t version) const { } result.impl->mutationIndex = 0; - result.impl->version = version; return result; }