From 7c2870d5f367ec57e5319a716e1a8bca944a8029 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Thu, 30 Apr 2020 22:04:03 -0400 Subject: [PATCH] wasi: avoid hard crash if start() is never called Prior to this commit, calling the WebAssembly instance's _start() export directly would hard crash the process because the memory was never configured. This commit adds an additional check that the memory is usable. With this commit, calling _start() directly will still lead to WASI exiting with a non-zero exit code, but Node does not crash. --- src/node_wasi.cc | 8 ++++---- test/wasi/test-no-start-call.js | 35 +++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 test/wasi/test-no-start-call.js diff --git a/src/node_wasi.cc b/src/node_wasi.cc index 0330656b29e926..3ad666cce2506d 100644 --- a/src/node_wasi.cc +++ b/src/node_wasi.cc @@ -1791,11 +1791,11 @@ uvwasi_errno_t WASI::backingStore(char** store, size_t* byte_length) { Local memory = PersistentToLocal::Strong(this->memory_); Local prop; - if (!memory->Get(env->context(), env->buffer_string()).ToLocal(&prop)) - return UVWASI_EINVAL; - - if (!prop->IsArrayBuffer()) + if (this->memory_.IsEmpty() || + !memory->Get(env->context(), env->buffer_string()).ToLocal(&prop) || + !prop->IsArrayBuffer()) { return UVWASI_EINVAL; + } Local ab = prop.As(); std::shared_ptr backing_store = ab->GetBackingStore(); diff --git a/test/wasi/test-no-start-call.js b/test/wasi/test-no-start-call.js new file mode 100644 index 00000000000000..e7fc23c75115de --- /dev/null +++ b/test/wasi/test-no-start-call.js @@ -0,0 +1,35 @@ +'use strict'; +const common = require('../common'); + +if (process.argv[2] === 'child') { + (async () => { + const fs = require('fs'); + const path = require('path'); + const { WASI } = require('wasi'); + const wasmDir = path.join(__dirname, 'wasm'); + const modulePath = path.join(wasmDir, 'main_args.wasm'); + const buffer = fs.readFileSync(modulePath); + const wasi = new WASI(); + const importObject = { wasi_snapshot_preview1: wasi.wasiImport }; + const { instance } = await WebAssembly.instantiate(buffer, importObject); + + // Verify that calling the _start() export instead of start() does not + // crash. The application will fail with a non-zero exit code. + instance.exports._start(); + })().then(common.mustCall()); +} else { + const assert = require('assert'); + const { spawnSync } = require('child_process'); + const child = spawnSync(process.execPath, [ + '--experimental-wasi-unstable-preview1', + '--experimental-wasm-bigint', + '--no-warnings', + __filename, + 'child' + ]); + + assert.strictEqual(child.stdout.toString(), ''); + assert.strictEqual(child.stderr.toString(), ''); + assert.strictEqual(child.signal, null); + assert.notStrictEqual(child.status, 0); +}