This commit is contained in:
Andras Schmelczer 2026-09-27 15:59:35 +01:00
commit f87ad0d786

View file

@ -89,6 +89,49 @@ test("content edited after planning is merged with the incoming snapshot", async
);
});
test("repeated large text replacements reuse WebAssembly memory", async () => {
// The replacement from fuzz-193329 exhausted reconcile-text 0.8.0's
// allocator over repeated merges, eventually stalling sync and trapping.
const original = (
" مرحباéשלום\t日本語\ncaféalphaalphaनमस्ते🦊🌍café\n" +
"🌍مرحبامرحباनमस्तेשלום\talphaalphacaféمرحبا🌍\r\n日本語مرحبا"
).repeat(128);
const replacement = await hashSnapshot({
content: bytes(
(
"alpha🌍éनमस्ते日本語שלום\uFEFFשלום\t\r\n" +
"\uFEFF🦊 🦊🌍नमस्ते\uFEFFéمرحبا\r\ncafé🌍é🌍"
).repeat(128)
)
});
const f = await fixture({ "a.md": original });
const expected = (await f.files.readSnapshot("a.md"))!;
const apply = async () => {
await f.disk.userWrite("a.md", bytes(original));
await f.files.applyChanges(structuredClone(f.database.state), {
a: { expected, replacement }
});
assert.deepEqual(f.disk.userFiles().get("a.md"), replacement.content);
assert.equal(
f.database.state.documents.a.observedHash,
replacement.hash
);
};
await apply(); // Warm up the module and its allocator before measuring.
const warmedMemory = process.memoryUsage.rss();
for (let repeat = 0; repeat < 4; repeat++) {
await apply();
// Measure resident memory because V8's external counter can omit WASM
// memory after GC. The old allocator grew ~150 MiB on every call.
const growth = process.memoryUsage.rss() - warmedMemory;
assert(
growth < 64 * 1024 * 1024,
`Resident memory grew by ${growth} bytes`
);
}
});
test("deleting the source after planning does not resurrect it", async () => {
const f = await fixture();
const next = structuredClone(f.database.state);