Skip to content

Commit

Permalink
chore: add failing test of slotToVal memory leak for watchPromise
Browse files Browse the repository at this point in the history
Liveslots has a bug (#10757) which leaks slotToVal entries when a
tracked Promise is still being held in virtual data (e.g. a
merely-virtual MapStore) at the time it becomes settled. This is
triggered by `watchPromise` because of the order in which we attach
two handlers: one which notices the resolution and is inhibited from
deleting the slotToVal entry, and a second which removes the Promise
from the (virtual) `promiseRegistrations` collection (thus enabling
the deletion). For any watched Promise that is resolved, we leave a
`slotToVal` entry (with an empty WeakRef) in RAM until the end of the
incarnation.

This commit adds a test.failing to demonstrate the presence of the
bug. Each time we watch and then resolve a promise, the slotToVal
table grows by one entry.

refs #10756
  • Loading branch information
warner committed Dec 20, 2024
1 parent e5813b9 commit 3a77937
Showing 1 changed file with 42 additions and 0 deletions.
42 changes: 42 additions & 0 deletions packages/swingset-liveslots/test/watch-promise.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import test from 'ava';

import { Far } from '@endo/marshal';
import { makePromiseKit } from '@endo/promise-kit';
import { setupTestLiveslots } from './liveslots-helpers.js';

const build = vatPowers => {
const { VatData } = vatPowers;
const { makeKindHandle, defineDurableKind, watchPromise } = VatData;

const kh = makeKindHandle('handler');
const init = () => ({});
const behavior = {
onFulfilled: _value => 0,
onRejected: _reason => 0,
};
const makeHandler = defineDurableKind(kh, init, behavior);

return Far('root', {
async run() {
const pr = makePromiseKit();
const handler = makeHandler();
watchPromise(pr.promise, handler);
pr.resolve('ignored');
},
});
};

test.failing('watched local promises should not leak slotToVal entries', async t => {
const { dispatchMessage, testHooks } = await setupTestLiveslots(
t,
build,
'vatA',
);
const { slotToVal } = testHooks;
const initial = slotToVal.size;

await dispatchMessage('run');
t.is(slotToVal.size, initial);
await dispatchMessage('run');
t.is(slotToVal.size, initial);
});

0 comments on commit 3a77937

Please sign in to comment.