Skip to content

Commit f206193

Browse files
devsneksam-github
authored andcommitted
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: #14927 PR-URL: #27246 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
1 parent cca375f commit f206193

6 files changed

+76
-11
lines changed

src/inspector_agent.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ void StartIoInterrupt(Isolate* isolate, void* agent) {
8888

8989

9090
#ifdef __POSIX__
91-
static void StartIoThreadWakeup(int signo) {
91+
static void StartIoThreadWakeup(int signo, siginfo_t* info, void* ucontext) {
9292
uv_sem_post(&start_io_thread_semaphore);
9393
}
9494

src/node.cc

+55-3
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,17 @@
7070
#include "node_report.h"
7171
#endif
7272

73+
#if defined(__APPLE__) || defined(__linux__)
74+
#define NODE_USE_V8_WASM_TRAP_HANDLER 1
75+
#else
76+
#define NODE_USE_V8_WASM_TRAP_HANDLER 0
77+
#endif
78+
79+
#if NODE_USE_V8_WASM_TRAP_HANDLER
80+
#include <atomic>
81+
#include "v8-wasm-trap-handler-posix.h"
82+
#endif // NODE_USE_V8_WASM_TRAP_HANDLER
83+
7384
// ========== global C headers ==========
7485

7586
#include <fcntl.h> // _O_RDWR
@@ -177,7 +188,8 @@ void WaitForInspectorDisconnect(Environment* env) {
177188
#endif
178189
}
179190

180-
void SignalExit(int signo) {
191+
#ifdef __POSIX__
192+
void SignalExit(int signo, siginfo_t* info, void* ucontext) {
181193
uv_tty_reset_mode();
182194
#ifdef __FreeBSD__
183195
// FreeBSD has a nasty bug, see RegisterSignalHandler for details
@@ -188,6 +200,7 @@ void SignalExit(int signo) {
188200
#endif
189201
raise(signo);
190202
}
203+
#endif // __POSIX__
191204

192205
MaybeLocal<Value> ExecuteBootstrapper(Environment* env,
193206
const char* id,
@@ -434,14 +447,39 @@ void LoadEnvironment(Environment* env) {
434447
USE(StartMainThreadExecution(env));
435448
}
436449

450+
#if NODE_USE_V8_WASM_TRAP_HANDLER
451+
static std::atomic<void (*)(int signo, siginfo_t* info, void* ucontext)>
452+
previous_sigsegv_action;
453+
454+
void TrapWebAssemblyOrContinue(int signo, siginfo_t* info, void* ucontext) {
455+
if (!v8::TryHandleWebAssemblyTrapPosix(signo, info, ucontext)) {
456+
auto prev = previous_sigsegv_action.load();
457+
if (prev != nullptr) {
458+
prev(signo, info, ucontext);
459+
} else {
460+
uv_tty_reset_mode();
461+
raise(signo);
462+
}
463+
}
464+
}
465+
#endif // NODE_USE_V8_WASM_TRAP_HANDLER
437466

438467
#ifdef __POSIX__
439468
void RegisterSignalHandler(int signal,
440-
void (*handler)(int signal),
469+
void (*handler)(int signal,
470+
siginfo_t* info,
471+
void* ucontext),
441472
bool reset_handler) {
473+
#if NODE_USE_V8_WASM_TRAP_HANDLER
474+
if (signal == SIGSEGV) {
475+
CHECK(previous_sigsegv_action.is_lock_free());
476+
previous_sigsegv_action.store(handler);
477+
return;
478+
}
479+
#endif // NODE_USE_V8_WASM_TRAP_HANDLER
442480
struct sigaction sa;
443481
memset(&sa, 0, sizeof(sa));
444-
sa.sa_handler = handler;
482+
sa.sa_sigaction = handler;
445483
#ifndef __FreeBSD__
446484
// FreeBSD has a nasty bug with SA_RESETHAND reseting the SA_SIGINFO, that is
447485
// in turn set for a libthr wrapper. This leads to a crash.
@@ -499,6 +537,20 @@ inline void PlatformInit() {
499537
RegisterSignalHandler(SIGINT, SignalExit, true);
500538
RegisterSignalHandler(SIGTERM, SignalExit, true);
501539

540+
#if NODE_USE_V8_WASM_TRAP_HANDLER
541+
// Tell V8 to disable emitting WebAssembly
542+
// memory bounds checks. This means that we have
543+
// to catch the SIGSEGV in TrapWebAssemblyOrContinue
544+
// and pass the signal context to V8.
545+
{
546+
struct sigaction sa;
547+
memset(&sa, 0, sizeof(sa));
548+
sa.sa_sigaction = TrapWebAssemblyOrContinue;
549+
CHECK_EQ(sigaction(SIGSEGV, &sa, nullptr), 0);
550+
}
551+
V8::EnableWebAssemblyTrapHandler(false);
552+
#endif // NODE_USE_V8_WASM_TRAP_HANDLER
553+
502554
// Raise the open file descriptor limit.
503555
struct rlimit lim;
504556
if (getrlimit(RLIMIT_NOFILE, &lim) == 0 && lim.rlim_cur != lim.rlim_max) {

src/node.h

+15
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@
6666

6767
#include <memory>
6868

69+
#ifdef __POSIX__
70+
#include <signal.h>
71+
#endif // __POSIX__
72+
6973
#define NODE_MAKE_VERSION(major, minor, patch) \
7074
((major) * 0x1000 + (minor) * 0x100 + (patch))
7175

@@ -816,6 +820,17 @@ class NODE_EXTERN AsyncResource {
816820
async_context async_context_;
817821
};
818822

823+
#ifdef __POSIX__
824+
// Register a signal handler without interrupting
825+
// any handlers that node itself needs.
826+
NODE_EXTERN
827+
void RegisterSignalHandler(int signal,
828+
void (*handler)(int signal,
829+
siginfo_t* info,
830+
void* ucontext),
831+
bool reset_handler = false);
832+
#endif // __POSIX__
833+
819834
} // namespace node
820835

821836
#endif // SRC_NODE_H_

src/node_internals.h

+1-4
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,8 @@ void PrintCaughtException(v8::Isolate* isolate,
9191
const v8::TryCatch& try_catch);
9292

9393
void WaitForInspectorDisconnect(Environment* env);
94-
void SignalExit(int signo);
9594
#ifdef __POSIX__
96-
void RegisterSignalHandler(int signal,
97-
void (*handler)(int signal),
98-
bool reset_handler = false);
95+
void SignalExit(int signal, siginfo_t* info, void* ucontext);
9996
#endif
10097

10198
std::string GetHumanReadableProcessName();

src/node_watchdog.cc

+3-2
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,9 @@ void* SigintWatchdogHelper::RunSigintWatchdog(void* arg) {
127127
return nullptr;
128128
}
129129

130-
131-
void SigintWatchdogHelper::HandleSignal(int signum) {
130+
void SigintWatchdogHelper::HandleSignal(int signum,
131+
siginfo_t* info,
132+
void* ucontext) {
132133
uv_sem_post(&instance.sem_);
133134
}
134135

src/node_watchdog.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ class SigintWatchdogHelper {
9999
bool stopping_;
100100

101101
static void* RunSigintWatchdog(void* arg);
102-
static void HandleSignal(int signum);
102+
static void HandleSignal(int signum, siginfo_t* info, void* ucontext);
103103
#else
104104
bool watchdog_disabled_;
105105
static BOOL WINAPI WinCtrlCHandlerRoutine(DWORD dwCtrlType);

0 commit comments

Comments
 (0)