Skip to content

Commit

Permalink
fix(liveslots): avoid slotToVal memory leak for watched promises
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 PR does not fix the underlying bug, but it rearranges the handler
order to avoid triggering it.

closes #10756
refs #10706
  • Loading branch information
warner committed Dec 20, 2024
1 parent 3a77937 commit 874196c
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 4 deletions.
16 changes: 13 additions & 3 deletions packages/swingset-liveslots/src/watchedPromises.js
Original file line number Diff line number Diff line change
Expand Up @@ -235,13 +235,23 @@ export function makeWatchedPromiseManager({
} else {
watchedPromiseTable.init(vpid, harden([[watcher, ...args]]));

promiseRegistrations.init(vpid, p);

// pseudoThen registers a settlement callback that will remove
// this promise from promiseRegistrations and
// watchedPromiseTable. To avoid triggering
// https://github.com/Agoric/agoric-sdk/issues/10757 and
// preventing slotToVal cleanup, the `pseudoThen()` should
// precede `maybeExportPromise()`. This isn't foolproof, but
// does mitigate in advance of a proper fix. See #10756 for
// details of this particular mitigation, and #10757 for the
// deeper bug.
pseudoThen(p, vpid);

// Ensure that this vat's promises are rejected at termination.
if (maybeExportPromise(vpid)) {
syscall.subscribe(vpid);
}

promiseRegistrations.init(vpid, p);
pseudoThen(p, vpid);
}
});
}
Expand Down
2 changes: 1 addition & 1 deletion packages/swingset-liveslots/test/watch-promise.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const build = vatPowers => {
});
};

test.failing('watched local promises should not leak slotToVal entries', async t => {
test('watched local promises should not leak slotToVal entries', async t => {
const { dispatchMessage, testHooks } = await setupTestLiveslots(
t,
build,
Expand Down

0 comments on commit 874196c

Please sign in to comment.