Skip to content

Commit

Permalink
feat(xsnap): parserBufferSize run-time option
Browse files Browse the repository at this point in the history
  • Loading branch information
dckc committed Mar 28, 2021
1 parent 445d327 commit e81292a
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 52 deletions.
41 changes: 27 additions & 14 deletions packages/xsnap/src/xsnap.c
Original file line number Diff line number Diff line change
Expand Up @@ -204,19 +204,7 @@ int main(int argc, char* argv[])
int error = 0;
int interval = 0;
int freeze = 0;
xsCreation _creation = {
16 * 1024 * 1024, /* initialChunkSize */
16 * 1024 * 1024, /* incrementalChunkSize */
1 * 1024 * 1024, /* initialHeapCount */
1 * 1024 * 1024, /* incrementalHeapCount */
4096, /* stackCount */
32000, /* keyCount */
1993, /* nameModulo */
127, /* symbolModulo */
8192 * 1024, /* parserBufferSize */
1993, /* parserTableModulo */
};
xsCreation* creation = &_creation;
int parserBufferSize = 8192 * 1024;

txSnapshot snapshot = {
SNAPSHOT_SIGNATURE,
Expand Down Expand Up @@ -279,6 +267,15 @@ int main(int argc, char* argv[])
return 1;
}
}
else if (!strcmp(argv[argi], "-s")) {
argi++;
if (argi < argc)
parserBufferSize = 1024 * atoi(argv[argi]);
else {
fxPrintUsage();
return 1;
}
}
else if (!strcmp(argv[argi], "-v")) {
printf("xsnap %s (XS %d.%d.%d)\n", XSNAP_VERSION, XS_MAJOR_VERSION, XS_MINOR_VERSION, XS_PATCH_VERSION);
return 0;
Expand All @@ -287,6 +284,21 @@ int main(int argc, char* argv[])
return 1;
}
}
fprintf(stderr, "@@parserBufferSize %d", parserBufferSize);
xsCreation _creation = {
16 * 1024 * 1024, /* initialChunkSize */
16 * 1024 * 1024, /* incrementalChunkSize */
1 * 1024 * 1024, /* initialHeapCount */
1 * 1024 * 1024, /* incrementalHeapCount */
4096, /* stackCount */
32000, /* keyCount */
1993, /* nameModulo */
127, /* symbolModulo */
parserBufferSize, /* parserBufferSize */
1993, /* parserTableModulo */
};
xsCreation* creation = &_creation;

if (gxCrankMeteringLimit) {
if (interval == 0)
interval = 1;
Expand Down Expand Up @@ -850,11 +862,12 @@ void fxPatchBuiltIns(txMachine* machine)

void fxPrintUsage()
{
printf("xsnap [-h] [-f] [-i <interval>] [-l <limit>] [-m] [-r <snapshot>] [-s] [-v]\n");
printf("xsnap [-h] [-f] [-i <interval>] [-l <limit>] [-s <size>] [-m] [-r <snapshot>] [-s] [-v]\n");
printf("\t-f: freeze the XS machine\n");
printf("\t-h: print this help message\n");
printf("\t-i <interval>: metering interval (default to 1)\n");
printf("\t-l <limit>: metering limit (default to none)\n");
printf("\t-s <size>: parser buffer size, in kB (default to 8192)\n");
printf("\t-r <snapshot>: read snapshot to create the XS machine\n");
printf("\t-v: print XS version\n");
}
Expand Down
10 changes: 9 additions & 1 deletion packages/xsnap/src/xsnap.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ function echoCommand(arg) {
* @param {(request:Uint8Array) => Promise<Uint8Array>} [options.handleCommand]
* @param {string=} [options.name]
* @param {boolean=} [options.debug]
* @param {number=} [options.parserBufferSize] in kB (must be an integer)
* @param {string=} [options.snapshot]
* @param {'ignore' | 'inherit'} [options.stdout]
* @param {'ignore' | 'inherit'} [options.stderr]
Expand All @@ -58,6 +59,7 @@ export function xsnap(options) {
name = '<unnamed xsnap worker>',
handleCommand = echoCommand,
debug = false,
parserBufferSize = undefined,
snapshot = undefined,
stdout = 'ignore',
stderr = 'ignore',
Expand All @@ -82,10 +84,16 @@ export function xsnap(options) {
/** @type {Deferred<void>} */
const vatExit = defer();

const args = snapshot ? ['-r', snapshot] : [];
const args = [];
if (snapshot) {
args.push('-r', snapshot);
}
if (meteringLimit) {
args.push('-l', `${meteringLimit}`);
}
if (parserBufferSize) {
args.push('-s', `${parserBufferSize}`);
}

const xsnapProcess = spawn(bin, args, {
stdio: ['ignore', stdout, stderr, 'pipe', 'pipe'],
Expand Down
64 changes: 27 additions & 37 deletions packages/xsnap/test/test-xsnap.js
Original file line number Diff line number Diff line change
Expand Up @@ -435,50 +435,40 @@ test('property name space exhaustion: orderly fail-stop', async t => {
}
});

test('parser buffer exhaustion: orderly fail-stop', async t => {
const grow = `
const send = it => issueCommand(ArrayBuffer.fromString(it));
let expr = '1+1';
(() => {
const grow = qty => `
const send = it => issueCommand(ArrayBuffer.fromString(JSON.stringify(it)));
let expr = \`"\${Array(${qty}).fill('abcd').join('')}"\`;
try {
for(;;) {
send(expr.length);
eval(expr);
expr = expr + ',' + expr;
}
eval(expr);
send(expr.length);
} catch (err) {
// buffer exhaustion should not be catchable!
send(err.message);
}
`;
for (const debug of [false, true]) {
const opts = options();
const vat = xsnap({ ...opts, debug });
t.teardown(() => vat.terminate());
// eslint-disable-next-line no-await-in-loop
await t.throwsAsync(vat.evaluate(grow), { message: /exited with code 7$/ });
t.deepEqual(opts.messages.slice(0, 19), [
'3',
'7',
'15',
'31',
'63',
'127',
'255',
'511',
'1023',
'2047',
'4095',
'8191',
'16383',
'32767',
'65535',
'131071',
'262143',
'524287',
'1048575',
]);
for (const [parserBufferSize, qty, failure] of [
[undefined, 100, null],
[undefined, 8192 * 1024 + 100, 'buffer overflow'],
[2, 10, null],
[2, 50000, 'buffer overflow'],
]) {
test(`parser buffer size ${parserBufferSize ||
'default'}k; rep ${qty}; debug ${debug}`, async t => {
const opts = options();
const vat = xsnap({ ...opts, debug, parserBufferSize });
t.teardown(() => vat.terminate());
const expected = failure ? [failure] : [qty * 4 + 2];
// eslint-disable-next-line no-await-in-loop
await t.notThrowsAsync(vat.evaluate(grow(qty)));
t.deepEqual(
expected,
opts.messages.map(txt => JSON.parse(txt)),
);
});
}
}
});
})();

(() => {
const challenges = [
Expand Down

0 comments on commit e81292a

Please sign in to comment.