Skip to content

Commit

Permalink
prevent vats from using send() to call themselves
Browse files Browse the repository at this point in the history
Vats normally use send() to queue messages for things they've
imported (either the exports of other vats, or kernel promises which
hopefully resolve to an export of some other vat).

But if a Vat uses send() on one if its own exports, that will queue a message
which will be delivered back to themselves later.

There's currently no good reason to do this, and it probably indicates the
vat got confused about what it was passing to send(). So for now, detect this
and throw an exception.

This might change when we add escalators later, but even then I can't
currently imagine a scenario in which we want to defer execution that isn't
more efficient to express with a local `Promise.resolve`.

closes Agoric#43
  • Loading branch information
warner committed May 15, 2019
1 parent ded91dc commit 274e6bc
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/kernel/vatManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,12 @@ export default function makeVatManager(vatID, syscallManager, setup, helpers) {
`targetSlot isn't really a slot ${JSON.stringify(targetSlot)}`,
);
}
if (targetSlot.type === 'export') {
// Disable send-to-self for now. It might be useful in the future, but
// I doubt it, and we can prevent some confusion by flagging a specific
// error here. See issue #43 for details.
throw new Error(`send() is calling itself, see issue #43`);
}
const target = mapOutbound(targetSlot);
if (!target) {
throw Error(
Expand Down
21 changes: 21 additions & 0 deletions test/test-kernel.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,27 @@ test('addImport', t => {
t.end();
});

test('outbound call to my own export should fail', async t => {
const kernel = buildKernel({ setImmediate });
const log = [];
let s;
function setup1(syscall) {
s = syscall;
function deliver(facetID, method, argsString, slots) {
log.push([facetID, method, argsString, slots]);
}
return { deliver };
}
kernel.addVat('vat1', setup1);

t.throws(
() => s.send({ type: 'export', id: 5 }, 'methodname', 'body', []),
/send\(\) is calling itself/,
);

t.end();
});

test('outbound call', async t => {
const kernel = buildKernel({ setImmediate });
const log = [];
Expand Down

0 comments on commit 274e6bc

Please sign in to comment.