Avoid signed overflow

This only happens at implausibly high version numbers, but the fix is straightforward so we'll just do it anyway.

Closes #84
This commit is contained in:
2026-09-23 11:36:12 -04:00
parent 8a16f9a6d6
commit 46d1f05333
2 changed files with 24 additions and 1 deletions
+1 -1
View File
@@ -5091,7 +5091,7 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
if (oldestExtantVersion < writeVersion - kMaxCorrectVersionWindow)
[[unlikely]] {
if (writeVersion > newestVersionFullPrecision + kNominalVersionWindow) {
if (writeVersion - kNominalVersionWindow > newestVersionFullPrecision) {
eraseTree(rootParent->children[0], &writeContext);
init(writeVersion - kNominalVersionWindow);
}
+23
View File
@@ -2,6 +2,7 @@
#include <cassert>
#include <cstdio>
#include <limits>
using namespace weaselab;
@@ -23,6 +24,28 @@ int main(void) {
int64_t bytes = cs.getBytes();
assert(bytes > 0);
// Regression: a write just below INT64_MAX must not overflow the nominal
// version window comparison and erase entries that reads still observe.
// Versions are only required to be >= 0, so this is valid input.
{
const int64_t imax = std::numeric_limits<int64_t>::max();
const int64_t v0 = imax - int64_t(1000000000);
ConflictSet nearMax(0);
ConflictSet::WriteRange w2;
w2.begin.p = (const uint8_t *)"key";
w2.begin.len = 3;
w2.end.len = 0;
nearMax.addWrites(&w2, 1, v0);
nearMax.addWrites(&w2, 0, imax);
ConflictSet::ReadRange r2;
r2.begin.p = (const uint8_t *)"key";
r2.begin.len = 3;
r2.end.len = 0;
r2.readVersion = v0 - 1;
nearMax.check(&r2, &result, 1);
assert(result == ConflictSet::Conflict);
}
ConflictSet::MetricsV1 *metrics;
int metricsCount;
cs.getMetricsV1(&metrics, &metricsCount);