src: enable V8's WASM trap handlers
This uses SIGSEGV handlers to catch WASM out of bound (OOB) memory accesses instead of inserting OOB checks inline, resulting in a 25%-30% speed increase. Note that installing a custom SIGSEGV handler will break this, resulting in potentially scary behaviour. Refs: https://github.com/nodejs/node/issues/14927 PR-URL: https://github.com/nodejs/node/pull/27246 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
This commit is contained in:
parent
cca375f4af
commit
f2061930c8
@ -88,7 +88,7 @@ void StartIoInterrupt(Isolate* isolate, void* agent) {
|
|||||||
|
|
||||||
|
|
||||||
#ifdef __POSIX__
|
#ifdef __POSIX__
|
||||||
static void StartIoThreadWakeup(int signo) {
|
static void StartIoThreadWakeup(int signo, siginfo_t* info, void* ucontext) {
|
||||||
uv_sem_post(&start_io_thread_semaphore);
|
uv_sem_post(&start_io_thread_semaphore);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
58
src/node.cc
58
src/node.cc
@ -70,6 +70,17 @@
|
|||||||
#include "node_report.h"
|
#include "node_report.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(__APPLE__) || defined(__linux__)
|
||||||
|
#define NODE_USE_V8_WASM_TRAP_HANDLER 1
|
||||||
|
#else
|
||||||
|
#define NODE_USE_V8_WASM_TRAP_HANDLER 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if NODE_USE_V8_WASM_TRAP_HANDLER
|
||||||
|
#include <atomic>
|
||||||
|
#include "v8-wasm-trap-handler-posix.h"
|
||||||
|
#endif // NODE_USE_V8_WASM_TRAP_HANDLER
|
||||||
|
|
||||||
// ========== global C headers ==========
|
// ========== global C headers ==========
|
||||||
|
|
||||||
#include <fcntl.h> // _O_RDWR
|
#include <fcntl.h> // _O_RDWR
|
||||||
@ -177,7 +188,8 @@ void WaitForInspectorDisconnect(Environment* env) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void SignalExit(int signo) {
|
#ifdef __POSIX__
|
||||||
|
void SignalExit(int signo, siginfo_t* info, void* ucontext) {
|
||||||
uv_tty_reset_mode();
|
uv_tty_reset_mode();
|
||||||
#ifdef __FreeBSD__
|
#ifdef __FreeBSD__
|
||||||
// FreeBSD has a nasty bug, see RegisterSignalHandler for details
|
// FreeBSD has a nasty bug, see RegisterSignalHandler for details
|
||||||
@ -188,6 +200,7 @@ void SignalExit(int signo) {
|
|||||||
#endif
|
#endif
|
||||||
raise(signo);
|
raise(signo);
|
||||||
}
|
}
|
||||||
|
#endif // __POSIX__
|
||||||
|
|
||||||
MaybeLocal<Value> ExecuteBootstrapper(Environment* env,
|
MaybeLocal<Value> ExecuteBootstrapper(Environment* env,
|
||||||
const char* id,
|
const char* id,
|
||||||
@ -434,14 +447,39 @@ void LoadEnvironment(Environment* env) {
|
|||||||
USE(StartMainThreadExecution(env));
|
USE(StartMainThreadExecution(env));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if NODE_USE_V8_WASM_TRAP_HANDLER
|
||||||
|
static std::atomic<void (*)(int signo, siginfo_t* info, void* ucontext)>
|
||||||
|
previous_sigsegv_action;
|
||||||
|
|
||||||
|
void TrapWebAssemblyOrContinue(int signo, siginfo_t* info, void* ucontext) {
|
||||||
|
if (!v8::TryHandleWebAssemblyTrapPosix(signo, info, ucontext)) {
|
||||||
|
auto prev = previous_sigsegv_action.load();
|
||||||
|
if (prev != nullptr) {
|
||||||
|
prev(signo, info, ucontext);
|
||||||
|
} else {
|
||||||
|
uv_tty_reset_mode();
|
||||||
|
raise(signo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // NODE_USE_V8_WASM_TRAP_HANDLER
|
||||||
|
|
||||||
#ifdef __POSIX__
|
#ifdef __POSIX__
|
||||||
void RegisterSignalHandler(int signal,
|
void RegisterSignalHandler(int signal,
|
||||||
void (*handler)(int signal),
|
void (*handler)(int signal,
|
||||||
|
siginfo_t* info,
|
||||||
|
void* ucontext),
|
||||||
bool reset_handler) {
|
bool reset_handler) {
|
||||||
|
#if NODE_USE_V8_WASM_TRAP_HANDLER
|
||||||
|
if (signal == SIGSEGV) {
|
||||||
|
CHECK(previous_sigsegv_action.is_lock_free());
|
||||||
|
previous_sigsegv_action.store(handler);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif // NODE_USE_V8_WASM_TRAP_HANDLER
|
||||||
struct sigaction sa;
|
struct sigaction sa;
|
||||||
memset(&sa, 0, sizeof(sa));
|
memset(&sa, 0, sizeof(sa));
|
||||||
sa.sa_handler = handler;
|
sa.sa_sigaction = handler;
|
||||||
#ifndef __FreeBSD__
|
#ifndef __FreeBSD__
|
||||||
// FreeBSD has a nasty bug with SA_RESETHAND reseting the SA_SIGINFO, that is
|
// FreeBSD has a nasty bug with SA_RESETHAND reseting the SA_SIGINFO, that is
|
||||||
// in turn set for a libthr wrapper. This leads to a crash.
|
// in turn set for a libthr wrapper. This leads to a crash.
|
||||||
@ -499,6 +537,20 @@ inline void PlatformInit() {
|
|||||||
RegisterSignalHandler(SIGINT, SignalExit, true);
|
RegisterSignalHandler(SIGINT, SignalExit, true);
|
||||||
RegisterSignalHandler(SIGTERM, SignalExit, true);
|
RegisterSignalHandler(SIGTERM, SignalExit, true);
|
||||||
|
|
||||||
|
#if NODE_USE_V8_WASM_TRAP_HANDLER
|
||||||
|
// Tell V8 to disable emitting WebAssembly
|
||||||
|
// memory bounds checks. This means that we have
|
||||||
|
// to catch the SIGSEGV in TrapWebAssemblyOrContinue
|
||||||
|
// and pass the signal context to V8.
|
||||||
|
{
|
||||||
|
struct sigaction sa;
|
||||||
|
memset(&sa, 0, sizeof(sa));
|
||||||
|
sa.sa_sigaction = TrapWebAssemblyOrContinue;
|
||||||
|
CHECK_EQ(sigaction(SIGSEGV, &sa, nullptr), 0);
|
||||||
|
}
|
||||||
|
V8::EnableWebAssemblyTrapHandler(false);
|
||||||
|
#endif // NODE_USE_V8_WASM_TRAP_HANDLER
|
||||||
|
|
||||||
// Raise the open file descriptor limit.
|
// Raise the open file descriptor limit.
|
||||||
struct rlimit lim;
|
struct rlimit lim;
|
||||||
if (getrlimit(RLIMIT_NOFILE, &lim) == 0 && lim.rlim_cur != lim.rlim_max) {
|
if (getrlimit(RLIMIT_NOFILE, &lim) == 0 && lim.rlim_cur != lim.rlim_max) {
|
||||||
|
15
src/node.h
15
src/node.h
@ -66,6 +66,10 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#ifdef __POSIX__
|
||||||
|
#include <signal.h>
|
||||||
|
#endif // __POSIX__
|
||||||
|
|
||||||
#define NODE_MAKE_VERSION(major, minor, patch) \
|
#define NODE_MAKE_VERSION(major, minor, patch) \
|
||||||
((major) * 0x1000 + (minor) * 0x100 + (patch))
|
((major) * 0x1000 + (minor) * 0x100 + (patch))
|
||||||
|
|
||||||
@ -816,6 +820,17 @@ class NODE_EXTERN AsyncResource {
|
|||||||
async_context async_context_;
|
async_context async_context_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef __POSIX__
|
||||||
|
// Register a signal handler without interrupting
|
||||||
|
// any handlers that node itself needs.
|
||||||
|
NODE_EXTERN
|
||||||
|
void RegisterSignalHandler(int signal,
|
||||||
|
void (*handler)(int signal,
|
||||||
|
siginfo_t* info,
|
||||||
|
void* ucontext),
|
||||||
|
bool reset_handler = false);
|
||||||
|
#endif // __POSIX__
|
||||||
|
|
||||||
} // namespace node
|
} // namespace node
|
||||||
|
|
||||||
#endif // SRC_NODE_H_
|
#endif // SRC_NODE_H_
|
||||||
|
@ -91,11 +91,8 @@ void PrintCaughtException(v8::Isolate* isolate,
|
|||||||
const v8::TryCatch& try_catch);
|
const v8::TryCatch& try_catch);
|
||||||
|
|
||||||
void WaitForInspectorDisconnect(Environment* env);
|
void WaitForInspectorDisconnect(Environment* env);
|
||||||
void SignalExit(int signo);
|
|
||||||
#ifdef __POSIX__
|
#ifdef __POSIX__
|
||||||
void RegisterSignalHandler(int signal,
|
void SignalExit(int signal, siginfo_t* info, void* ucontext);
|
||||||
void (*handler)(int signal),
|
|
||||||
bool reset_handler = false);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::string GetHumanReadableProcessName();
|
std::string GetHumanReadableProcessName();
|
||||||
|
@ -127,8 +127,9 @@ void* SigintWatchdogHelper::RunSigintWatchdog(void* arg) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SigintWatchdogHelper::HandleSignal(int signum,
|
||||||
void SigintWatchdogHelper::HandleSignal(int signum) {
|
siginfo_t* info,
|
||||||
|
void* ucontext) {
|
||||||
uv_sem_post(&instance.sem_);
|
uv_sem_post(&instance.sem_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ class SigintWatchdogHelper {
|
|||||||
bool stopping_;
|
bool stopping_;
|
||||||
|
|
||||||
static void* RunSigintWatchdog(void* arg);
|
static void* RunSigintWatchdog(void* arg);
|
||||||
static void HandleSignal(int signum);
|
static void HandleSignal(int signum, siginfo_t* info, void* ucontext);
|
||||||
#else
|
#else
|
||||||
bool watchdog_disabled_;
|
bool watchdog_disabled_;
|
||||||
static BOOL WINAPI WinCtrlCHandlerRoutine(DWORD dwCtrlType);
|
static BOOL WINAPI WinCtrlCHandlerRoutine(DWORD dwCtrlType);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user