diff --git a/ConflictSet.cpp b/ConflictSet.cpp index 1f0195d..20193e8 100644 --- a/ConflictSet.cpp +++ b/ConflictSet.cpp @@ -3928,7 +3928,7 @@ checkMaxVersion(Node *root, Node *node, InternalVersionT oldestVersion, bool &success, ConflictSet::Impl *impl) { checkVersionsGeqOldestExtant(node, InternalVersionT(impl->oldestExtantVersion)); - auto expected = InternalVersionT::zero; + auto expected = oldestVersion; if (node->entryPresent) { expected = std::max(expected, node->entry.pointVersion); } @@ -4151,26 +4151,42 @@ int main(void) { printTree(); } #ifdef ENABLE_FUZZ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - TestDriver driver{data, size}; + Arbitrary arbitrary({data, size}); + TestDriver driver1{arbitrary}; + TestDriver driver2{arbitrary}; + bool done1 = false; + bool done2 = false; for (;;) { - bool done = driver.next(); - if (!driver.ok) { - debugPrintDot(stdout, driver.cs.root, &driver.cs); - fflush(stdout); - abort(); + if (!done1) { + done1 = driver1.next(); + if (!driver1.ok) { + debugPrintDot(stdout, driver1.cs.root, &driver1.cs); + fflush(stdout); + abort(); + } + if (!checkCorrectness(driver1.cs.root, driver1.cs.oldestVersion, + &driver1.cs)) { + debugPrintDot(stdout, driver1.cs.root, &driver1.cs); + fflush(stdout); + abort(); + } } -#if DEBUG_VERBOSE && !defined(NDEBUG) - fprintf(stderr, "Check correctness\n"); -#endif - bool success = - checkCorrectness(driver.cs.root, driver.cs.oldestVersion, &driver.cs); - if (!success) { - debugPrintDot(stdout, driver.cs.root, &driver.cs); - fflush(stdout); - abort(); + if (!done2) { + done2 = driver2.next(); + if (!driver2.ok) { + debugPrintDot(stdout, driver2.cs.root, &driver2.cs); + fflush(stdout); + abort(); + } + if (!checkCorrectness(driver2.cs.root, driver2.cs.oldestVersion, + &driver2.cs)) { + debugPrintDot(stdout, driver2.cs.root, &driver2.cs); + fflush(stdout); + abort(); + } } - if (done) { + if (done1 && done2) { break; } } diff --git a/Internal.h b/Internal.h index ac54e62..e86f8bb 100644 --- a/Internal.h +++ b/Internal.h @@ -580,11 +580,10 @@ namespace { template struct TestDriver { - Arbitrary arbitrary; - explicit TestDriver(const uint8_t *data, size_t size) - : arbitrary({data, size}) {} + Arbitrary *arbitrary; + explicit TestDriver(Arbitrary &a) : arbitrary(&a) {} - int64_t oldestVersion = arbitrary.next(); + int64_t oldestVersion = arbitrary->next(); int64_t writeVersion = oldestVersion; ConflictSetImpl cs{oldestVersion}; ReferenceImpl refImpl{oldestVersion}; @@ -593,33 +592,34 @@ struct TestDriver { bool ok = true; - const int prefixLen = arbitrary.bounded(512); - const int prefixByte = arbitrary.randT(); + const int prefixLen = arbitrary->bounded(512); + const int prefixByte = arbitrary->randT(); // Call until it returns true, for "done". Check internal invariants etc // between calls to next. bool next() { assert(cs.getBytes() >= 0); - if (!arbitrary.hasEntropy()) { + if (!arbitrary->hasEntropy()) { return true; } Arena arena; { - int numPointWrites = arbitrary.bounded(100); - int numRangeWrites = arbitrary.bounded(100); - int64_t v = (writeVersion += arbitrary.bounded(10) ? arbitrary.bounded(10) - : arbitrary.next()); + int numPointWrites = arbitrary->bounded(100); + int numRangeWrites = arbitrary->bounded(100); + int64_t v = + (writeVersion += + arbitrary->bounded(10) ? arbitrary->bounded(10) : arbitrary->next()); auto *writes = new (arena) ConflictSet::WriteRange[numPointWrites + numRangeWrites]; auto keys = set(arena); while (int(keys.size()) < numPointWrites + numRangeWrites * 2) { - if (!arbitrary.hasEntropy()) { + if (!arbitrary->hasEntropy()) { return true; } - int keyLen = prefixLen + arbitrary.bounded(kMaxKeySuffixLen); + int keyLen = prefixLen + arbitrary->bounded(kMaxKeySuffixLen); auto *begin = new (arena) uint8_t[keyLen]; memset(begin, prefixByte, prefixLen); - arbitrary.randomBytes(begin + prefixLen, keyLen - prefixLen); + arbitrary->randomBytes(begin + prefixLen, keyLen - prefixLen); keys.insert(std::string_view((const char *)begin, keyLen)); } @@ -629,7 +629,7 @@ struct TestDriver { rangesRemaining = numRangeWrites; pointsRemaining > 0 || rangesRemaining > 0; ++i) { bool pointRead = pointsRemaining > 0 && rangesRemaining > 0 - ? bool(arbitrary.bounded(2)) + ? bool(arbitrary->bounded(2)) : pointsRemaining > 0; if (pointRead) { assert(pointsRemaining > 0); @@ -667,14 +667,14 @@ struct TestDriver { // Test non-canonical writes if (numPointWrites > 0) { - int overlaps = arbitrary.bounded(numPointWrites); + int overlaps = arbitrary->bounded(numPointWrites); for (int i = 0; i < numPointWrites + numRangeWrites && overlaps > 0; ++i) { if (writes[i].end.len == 0) { - int keyLen = prefixLen + arbitrary.bounded(kMaxKeySuffixLen); + int keyLen = prefixLen + arbitrary->bounded(kMaxKeySuffixLen); auto *begin = new (arena) uint8_t[keyLen]; memset(begin, prefixByte, prefixLen); - arbitrary.randomBytes(begin + prefixLen, keyLen - prefixLen); + arbitrary->randomBytes(begin + prefixLen, keyLen - prefixLen); writes[i].end.len = keyLen; writes[i].end.p = begin; auto c = @@ -692,10 +692,10 @@ struct TestDriver { } } } - if (arbitrary.bounded(2)) { + if (arbitrary->bounded(2)) { // Shuffle writes for (int i = numPointWrites + numRangeWrites - 1; i > 0; --i) { - int j = arbitrary.bounded(i + 1); + int j = arbitrary->bounded(i + 1); if (i != j) { using std::swap; swap(writes[i], writes[j]); @@ -704,7 +704,7 @@ struct TestDriver { } oldestVersion += - arbitrary.bounded(10) ? arbitrary.bounded(10) : arbitrary.next(); + arbitrary->bounded(10) ? arbitrary->bounded(10) : arbitrary->next(); oldestVersion = std::min(oldestVersion, writeVersion); #ifdef THREAD_TEST @@ -739,24 +739,24 @@ struct TestDriver { #endif } { - int numPointReads = arbitrary.bounded(100); - int numRangeReads = arbitrary.bounded(100); + int numPointReads = arbitrary->bounded(100); + int numRangeReads = arbitrary->bounded(100); - int64_t v = std::max(writeVersion - (arbitrary.bounded(10) - ? arbitrary.bounded(10) - : arbitrary.next()), + int64_t v = std::max(writeVersion - (arbitrary->bounded(10) + ? arbitrary->bounded(10) + : arbitrary->next()), 0); auto *reads = new (arena) ConflictSet::ReadRange[numPointReads + numRangeReads]; auto keys = set(arena); while (int(keys.size()) < numPointReads + numRangeReads * 2) { - if (!arbitrary.hasEntropy()) { + if (!arbitrary->hasEntropy()) { return true; } - int keyLen = prefixLen + arbitrary.bounded(kMaxKeySuffixLen); + int keyLen = prefixLen + arbitrary->bounded(kMaxKeySuffixLen); auto *begin = new (arena) uint8_t[keyLen]; memset(begin, prefixByte, prefixLen); - arbitrary.randomBytes(begin + prefixLen, keyLen - prefixLen); + arbitrary->randomBytes(begin + prefixLen, keyLen - prefixLen); keys.insert(std::string_view((const char *)begin, keyLen)); } @@ -765,7 +765,7 @@ struct TestDriver { for (int pointsRemaining = numPointReads, rangesRemaining = numRangeReads; pointsRemaining > 0 || rangesRemaining > 0; ++i) { bool pointRead = pointsRemaining > 0 && rangesRemaining > 0 - ? bool(arbitrary.bounded(2)) + ? bool(arbitrary->bounded(2)) : pointsRemaining > 0; if (pointRead) { assert(pointsRemaining > 0); diff --git a/TestDriver.cpp b/TestDriver.cpp index e1d24b3..0c9db40 100644 --- a/TestDriver.cpp +++ b/TestDriver.cpp @@ -13,25 +13,58 @@ int main(int argc, char **argv) { std::stringstream buffer; buffer << t.rdbuf(); auto str = buffer.str(); - TestDriver driver{(const uint8_t *)str.data(), - str.size()}; - while (!driver.next()) - ; - if (!driver.ok) { - abort(); + Arbitrary arbitrary({(const uint8_t *)str.data(), str.size()}); + TestDriver driver1{arbitrary}; + TestDriver driver2{arbitrary}; + bool done1 = false; + bool done2 = false; + for (;;) { + if (!done1) { + done1 = driver1.next(); + if (!driver1.ok) { + abort(); + } + } + if (!done2) { + done2 = driver2.next(); + if (!driver2.ok) { + abort(); + } + } + if (done1 && done2) { + break; + } } - ConflictSet::MetricsV1 *metrics; - int metricsCount; - driver.cs.getMetricsV1(&metrics, &metricsCount); - printf("#################### METRICS FOR %s ####################\n", - argv[i]); - for (int i = 0; i < metricsCount; ++i) { - printf("# HELP %s %s\n", metrics[i].name, metrics[i].help); - printf("# TYPE %s %s\n", metrics[i].name, - metrics[i].type == metrics[i].Counter ? "counter" : "gauge"); - printf("%s %g\n", metrics[i].name, metrics[i].getValue()); + { + ConflictSet::MetricsV1 *metrics; + int metricsCount; + driver1.cs.getMetricsV1(&metrics, &metricsCount); + printf("#################### METRICS for ConflictSet 1 for %s " + "####################\n", + argv[i]); + for (int i = 0; i < metricsCount; ++i) { + printf("# HELP %s %s\n", metrics[i].name, metrics[i].help); + printf("# TYPE %s %s\n", metrics[i].name, + metrics[i].type == metrics[i].Counter ? "counter" : "gauge"); + printf("%s %g\n", metrics[i].name, metrics[i].getValue()); + } + puts(""); + } + { + ConflictSet::MetricsV1 *metrics; + int metricsCount; + driver2.cs.getMetricsV1(&metrics, &metricsCount); + printf("#################### METRICS for ConflictSet 2 for %s " + "####################\n", + argv[i]); + for (int i = 0; i < metricsCount; ++i) { + printf("# HELP %s %s\n", metrics[i].name, metrics[i].help); + printf("# TYPE %s %s\n", metrics[i].name, + metrics[i].type == metrics[i].Counter ? "counter" : "gauge"); + printf("%s %g\n", metrics[i].name, metrics[i].getValue()); + } + puts(""); } - puts(""); } }