src: handle wasm out of bound in osx will raise SIGBUS correctly

fix: #46559
OSX will raise both SIGBUS and SIGSEGV when out of bound memory visit,
This commit set sigaction in OSX for two signals to handle this.

PR-URL: https://github.com/nodejs/node/pull/46561
Fixes: https://github.com/nodejs/node/issues/46559
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Darshan Sen <raisinten@gmail.com>
Reviewed-By: Minwoo Jung <nodecorelab@gmail.com>
Reviewed-By: Michael Dawson <midawson@redhat.com>
This commit is contained in:
Congcong Cai 2023-06-12 16:50:21 +02:00 committed by GitHub
parent bd7a8087a5
commit ed92b1fdaf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 51 additions and 1 deletions

View File

@ -362,10 +362,19 @@ static LONG TrapWebAssemblyOrContinue(EXCEPTION_POINTERS* exception) {
}
#else
static std::atomic<sigaction_cb> previous_sigsegv_action;
// TODO(align behavior between macos and other in next major version)
#if defined(__APPLE__)
static std::atomic<sigaction_cb> previous_sigbus_action;
#endif // __APPLE__
void TrapWebAssemblyOrContinue(int signo, siginfo_t* info, void* ucontext) {
if (!v8::TryHandleWebAssemblyTrapPosix(signo, info, ucontext)) {
#if defined(__APPLE__)
sigaction_cb prev = signo == SIGBUS ? previous_sigbus_action.load()
: previous_sigsegv_action.load();
#else
sigaction_cb prev = previous_sigsegv_action.load();
#endif // __APPLE__
if (prev != nullptr) {
prev(signo, info, ucontext);
} else {
@ -395,6 +404,15 @@ void RegisterSignalHandler(int signal,
previous_sigsegv_action.store(handler);
return;
}
// TODO(align behavior between macos and other in next major version)
#if defined(__APPLE__)
if (signal == SIGBUS) {
CHECK(previous_sigbus_action.is_lock_free());
CHECK(!reset_handler);
previous_sigbus_action.store(handler);
return;
}
#endif // __APPLE__
#endif // NODE_USE_V8_WASM_TRAP_HANDLER
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
@ -551,7 +569,7 @@ static void PlatformInit(ProcessInitializationFlags::Flags flags) {
#else
// Tell V8 to disable emitting WebAssembly
// memory bounds checks. This means that we have
// to catch the SIGSEGV in TrapWebAssemblyOrContinue
// to catch the SIGSEGV/SIGBUS in TrapWebAssemblyOrContinue
// and pass the signal context to V8.
{
struct sigaction sa;
@ -559,6 +577,10 @@ static void PlatformInit(ProcessInitializationFlags::Flags flags) {
sa.sa_sigaction = TrapWebAssemblyOrContinue;
sa.sa_flags = SA_SIGINFO;
CHECK_EQ(sigaction(SIGSEGV, &sa, nullptr), 0);
// TODO(align behavior between macos and other in next major version)
#if defined(__APPLE__)
CHECK_EQ(sigaction(SIGBUS, &sa, nullptr), 0);
#endif
}
#endif // defined(_WIN32)
V8::EnableWebAssemblyTrapHandler(false);

BIN
test/fixtures/out-of-bound.wasm vendored Normal file

Binary file not shown.

16
test/fixtures/out-of-bound.wat vendored Normal file
View File

@ -0,0 +1,16 @@
(module
(type $none_=>_none (func))
(memory $0 1)
(export "_start" (func $_start))
(func $_start
memory.size
i32.const 64
i32.mul
i32.const 1024
i32.mul
i32.const 3
i32.sub
i32.load
drop
)
)

View File

@ -0,0 +1,12 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const fixtures = require('../common/fixtures');
const buffer = fixtures.readSync('out-of-bound.wasm');
WebAssembly.instantiate(buffer, {}).then(common.mustCall((results) => {
assert.throws(() => {
results.instance.exports._start();
}, WebAssembly.RuntimeError('memory access out of bounds'));
}));