Skip to content

Commit

Permalink
wasi,worker: handle termination exception
Browse files Browse the repository at this point in the history
Be careful when emitting the 'beforeExit' event. It's not allowed to
call into the runtime when a termination exception is pending.

Fixes: #33377

PR-URL: #33386
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: Richard Lau <[email protected]>
Reviewed-By: Benjamin Gruenbaum <[email protected]>
Reviewed-By: Anna Henningsen <[email protected]>
Reviewed-By: James M Snell <[email protected]>
  • Loading branch information
bnoordhuis authored and codebytere committed Jul 8, 2020
1 parent 33984d6 commit 7df79f4
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 7 deletions.
13 changes: 8 additions & 5 deletions src/api/hooks.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,14 @@ void EmitBeforeExit(Environment* env) {

HandleScope handle_scope(env->isolate());
Context::Scope context_scope(env->context());
Local<Value> exit_code = env->process_object()
->Get(env->context(), env->exit_code_string())
.ToLocalChecked()
->ToInteger(env->context())
.ToLocalChecked();

Local<Value> exit_code_v;
if (!env->process_object()->Get(env->context(), env->exit_code_string())
.ToLocal(&exit_code_v)) return;

Local<Integer> exit_code;
if (!exit_code_v->ToInteger(env->context()).ToLocal(&exit_code)) return;

ProcessEmit(env, "beforeExit", exit_code).ToLocalChecked();
}

Expand Down
10 changes: 8 additions & 2 deletions src/node_process_events.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,16 @@ MaybeLocal<Value> ProcessEmit(Environment* env,
const char* event,
Local<Value> message) {
// Send message to enable debug in cluster workers
Local<Object> process = env->process_object();
Isolate* isolate = env->isolate();
Local<Value> argv[] = {OneByteString(isolate, event), message};

Local<String> event_string;
if (!String::NewFromOneByte(isolate,
reinterpret_cast<const uint8_t*>(event),
NewStringType::kNormal)
.ToLocal(&event_string)) return MaybeLocal<Value>();

Local<Object> process = env->process_object();
Local<Value> argv[] = {event_string, message};
return MakeCallback(isolate, process, "emit", arraysize(argv), argv, {0, 0});
}

Expand Down
44 changes: 44 additions & 0 deletions test/wasi/test-wasi-worker-terminate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Flags: --experimental-wasi-unstable-preview1
'use strict';

const common = require('../common');
const assert = require('assert');
const { WASI } = require('wasi');
const { Worker, parentPort } = require('worker_threads');

// void _start(void) { for (;;); }
const bytecode = new Uint8Array([
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60,
0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0x04, 0x05, 0x01, 0x70, 0x01, 0x01,
0x01, 0x05, 0x03, 0x01, 0x00, 0x02, 0x06, 0x08, 0x01, 0x7f, 0x01, 0x41,
0x80, 0x88, 0x04, 0x0b, 0x07, 0x13, 0x02, 0x06, 0x6d, 0x65, 0x6d, 0x6f,
0x72, 0x79, 0x02, 0x00, 0x06, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00,
0x00, 0x0a, 0x09, 0x01, 0x07, 0x00, 0x03, 0x40, 0x0c, 0x00, 0x0b, 0x0b,
0x00, 0x10, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x01, 0x09, 0x01, 0x00, 0x06,
0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x2f, 0x09, 0x70, 0x72, 0x6f,
0x64, 0x75, 0x63, 0x65, 0x72, 0x73, 0x01, 0x0c, 0x70, 0x72, 0x6f, 0x63,
0x65, 0x73, 0x73, 0x65, 0x64, 0x2d, 0x62, 0x79, 0x01, 0x05, 0x63, 0x6c,
0x61, 0x6e, 0x67, 0x0f, 0x31, 0x30, 0x2e, 0x30, 0x2e, 0x30, 0x2d, 0x34,
0x75, 0x62, 0x75, 0x6e, 0x74, 0x75, 0x31
]);

// Do not use isMainThread so that this test itself can be run inside a Worker.
if (!process.env.HAS_STARTED_WORKER) {
process.env.HAS_STARTED_WORKER = 1;
const worker = new Worker(__filename);
worker.once('message', (message) => {
assert.strictEqual(message, 'start');
setTimeout(() => worker.terminate(), common.platformTimeout(50));
});
} else {
go();
}

async function go() {
const wasi = new WASI({ returnOnExit: true });
const imports = { wasi_snapshot_preview1: wasi.wasiImport };
const module = await WebAssembly.compile(bytecode);
const instance = await WebAssembly.instantiate(module, imports);
parentPort.postMessage('start');
wasi.start(instance);
}

0 comments on commit 7df79f4

Please sign in to comment.