From 8de8111f8c39e3f965b0c919a40b7e897c58dcdd Mon Sep 17 00:00:00 2001 From: Brian Warner Date: Mon, 24 Jun 2024 17:32:24 -0700 Subject: [PATCH] fix(swingset): retire unreachable orphans If a kernel object ("koid", the object subset of krefs) is unreachable, and then becomes orphaned (either because the owning vat was terminated, or called `syscall.abandonExports`, or was upgraded and the koid was ephemeral), then retire it immediately. The argument is that the previously-owning vat can never again talk about the object, so as far as the rest of the world is concerned, the object has been retired. And because the owning vat can't retire it by itself, the kernel needs to do the retirement. TODO: do we handle entering this state from the other direction: when an orphaned object becomes unreachable? `processRefcounts()` has something but I'm not sure it's sufficient. closes #7212 --- packages/SwingSet/src/kernel/state/kernelKeeper.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/SwingSet/src/kernel/state/kernelKeeper.js b/packages/SwingSet/src/kernel/state/kernelKeeper.js index 4e6480decf35..cac7c90514ac 100644 --- a/packages/SwingSet/src/kernel/state/kernelKeeper.js +++ b/packages/SwingSet/src/kernel/state/kernelKeeper.js @@ -599,14 +599,23 @@ export default function makeKernelKeeper(kernelStorage, kernelSlog) { } function orphanKernelObjects(krefs, oldVat) { + const retiredKrefs = []; for (const kref of krefs) { const ownerKey = `${kref}.owner`; const ownerVat = kvStore.get(ownerKey); ownerVat === oldVat || Fail`export ${kref} not owned by old vat`; kvStore.delete(ownerKey); - // note that we do not delete the object here: it will be + if (getObjectRefCount(kref).reachable === 0) { + // unreachable orphans are retired: the original exporting vat + // won't be around to retire it + retiredKrefs.push(kref); + } + // else, note that we do not delete the object here: it will be // collected if/when all other references are dropped } + if (retiredKrefs.length) { + retireKernelObjects(retiredKrefs); + } } function deleteKernelObject(koid) {