GC sensing via virtual-object method identity
See original GitHub issueWhile reviewing #4618, I think I spotted a problem with our plan to prevent userspace from sensing GC. Imagine a stripped-down Purse kind:
const makePurseKit = makeKind('name', () => { currentBalance: 0 }, {
const purse = { deposit: () => stuff };
const depositFacet = { receive: purse.deposit };
return { purse, depositFacet };
});
Now imagine that userspace does:
let p1kit = makePurseKit();
let rx1 = p1kit.purse.deposit;
virtualCollection.set(key, p1kit);
let p1kit = null;
// now GC may or may not happen
let p2kit = virtualCollection.get(key);
let rx2 = p2kit.purse.deposit;
rx1 === rx2;
If GC does not happen, and the p1kit cohort is still in memory, the virtualCollection.get() will call the actualizer (so it can’t sense GC by counting invocations) and throw away its value, and p2kit will be the same object as p1kit (although userspace threw away p1kit so it can’t sense this directly). In this case, rx2 will be the same as rx1.
If GC did happen, we’ll still have the deposit method, but the purse (and indeed the whole cohort) will be gone. So the vc.get() will use the actualizer value, which will have a new deposit method, which will not be the same as rx1. This would mean userspace can sense GC when it’s supposed to be oblivious to it.
And, now that I write it, we don’t need multiple facets at all: the same problem would occur with just purse.
We established a weakmap from each Representative to the cohort, so that userspace holding on to e.g. p1kit.purse would be sufficient to keep the whole p1kit cohort in memory, preventing them from using this to sense GC. But that doesn’t help for interior values.
I’m not seeing an obvious way to fix this. Any new object created by actualize might be comparable, and I don’t think we have a way for makeKind to find them all (and use them as WeakMap keys to keep the cohort alive).
This feels a bit like the “every Presence is unique and userspace shouldn’t ever compare them” world we were in a year ago, which we escaped by preventing userspace from using distinct Presence Objects as WeakMap keys (the inescapableGlobals.WeakMap = VrefAwareWeakMap trick). But those Presences didn’t have internal structure that could be used for identity comparison. And, now that I think about it, #2069 auxdata might open up the same sort of problem on Presences.
Issue Analytics
- State:
- Created a year ago
- Comments:20 (20 by maintainers)

Top Related StackOverflow Question
Would it work for
Farto always use the same prototype object for a given iface string?Btw, it occurs to me that in https://github.com/Agoric/agoric-sdk/issues/5000 where I talk about GC sensing through userland WeakMap based on return override + private field stamping, the solution I propose relies on the ability to explicitly create all objects that should be prevented from such trick. The problem is that this wouldn’t be compatible with any functions, as you can mint those through
Object.create. If no functions are per instance (like I believe it might be the case for Far classes), then we should be good. Something to keep in mind.