Skip to content

Commit

Permalink
add test of fail-to-retire-presence bug
Browse files Browse the repository at this point in the history
refs #7355
  • Loading branch information
warner committed Apr 9, 2023
1 parent 4b8fdac commit 27dce5e
Showing 1 changed file with 87 additions and 0 deletions.
87 changes: 87 additions & 0 deletions packages/swingset-liveslots/test/test-liveslots-mock-gc.js
Original file line number Diff line number Diff line change
Expand Up @@ -396,3 +396,90 @@ for (const firstType of ['object', 'collection']) {
}

// test('double-free', doublefreetest, { firstType: 'object', lastType: 'collection', order: 'first->last' });

test('retirement', async t => {
const { syscall, fakestore, log } = buildSyscall();
const gcTools = makeMockGC();

// A is a weak collection, with one entry, whose key is B (a
// Presence). We drop the RAM pillar for B and do a BOYD, which
// should provoke a syscall.dropImports. Then, when we delete A (by
// dropping the RAM pillar), the next BOYD should see a
// `syscall.retireImports`.

let weakmapA;
let presenceB;

function buildRootObject(vatPowers) {
const { VatData } = vatPowers;
const { makeScalarBigWeakMapStore } = VatData;

weakmapA = makeScalarBigWeakMapStore();

return Far('root', {
add: p => {
presenceB = p;
weakmapA.init(presenceB, 'value');
},
});
}

const makeNS = () => ({ buildRootObject });
const ls = makeLiveSlots(syscall, 'vatA', {}, {}, gcTools, undefined, makeNS);
const { dispatch, testHooks } = ls;
const { valToSlot } = testHooks;

await dispatch(makeStartVat(kser()));
log.length = 0;
const weakmapAvref = valToSlot.get(weakmapA);
console.log(weakmapAvref);
const { subid } = parseVatSlot(weakmapAvref);
const collectionID = String(subid);

const rootA = 'o+0';
const presenceBvref = 'o-1';
await dispatch(makeMessage(rootA, 'add', [kslot(presenceBvref)]));
log.length = 0;

// the fact that weakmapA can recognize presenceA is recorded in a
// vatstore key
const recognizerKey = `vom.ir.${presenceBvref}|${collectionID}`;
t.is(fakestore.get(recognizerKey), '1');

// tell mockGC that userspace has dropped presenceB
gcTools.kill(presenceB);
gcTools.flushAllFRs();

await dispatch(makeBringOutYourDead());
const priorKey = `vom.ir.${presenceBvref}|`;

t.deepEqual(log.splice(0), [
// when a Presence is dropped, scanForDeadObjects can't drop the
// underlying vref import until it knows that virtual data isn't
// holding a reference, so we expect a refcount check
{ type: 'vatstoreGet', key: `vom.rc.${presenceBvref}`, result: undefined },

// the vref is now in importsToDrop, but since this commonly means
// it can be retired too, scanForDeadObjects goes ahead and checks
// for recognizers
{ type: 'vatstoreGetNextKey', priorKey, result: recognizerKey },

// it found a recognizer, so the vref cannot be retired
// yet. scanForDeadObjects finishes the BOYD by emitting the
// dropImports, but should keep watching for an opportunity to
// retire it too
{ type: 'dropImports', slots: [presenceBvref] },
]);

// now tell mockGC that we're dropping the weakmap too
gcTools.kill(weakmapA);
gcTools.flushAllFRs();

// this will provoke the deletion of the collection and all its
// data. It should *also* trigger a syscall.retireImports of the
// no-longer-recognizable key
await dispatch(makeBringOutYourDead());
const retires = log.filter(e => e.type === 'retireImports');
console.log(retires);
t.deepEqual(retires, [{ type: 'retireImports', slots: [presenceBvref] }]);
});

0 comments on commit 27dce5e

Please sign in to comment.