Skip to content

Commit e256204

Browse files
committed
src: reset SIGSEGV handler before crashing
Without this, we would re-enter the signal handler immediately after re-raising the signal, leading to an infinite loop. PR-URL: #27775 Refs: #27246 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Rich Trott <[email protected]>
1 parent e6b3ec3 commit e256204

File tree

3 files changed

+36
-0
lines changed

3 files changed

+36
-0
lines changed

src/node.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,12 @@ void TrapWebAssemblyOrContinue(int signo, siginfo_t* info, void* ucontext) {
487487
if (prev != nullptr) {
488488
prev(signo, info, ucontext);
489489
} else {
490+
// Reset to the default signal handler, i.e. cause a hard crash.
491+
struct sigaction sa;
492+
memset(&sa, 0, sizeof(sa));
493+
sa.sa_handler = SIG_DFL;
494+
CHECK_EQ(sigaction(signo, &sa, nullptr), 0);
495+
490496
ResetStdio();
491497
raise(signo);
492498
}

src/node_process_methods.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ static void Abort(const FunctionCallbackInfo<Value>& args) {
6363
Abort();
6464
}
6565

66+
// For internal testing only, not exposed to userland.
67+
static void CauseSegfault(const FunctionCallbackInfo<Value>& args) {
68+
// This should crash hard all platforms.
69+
*static_cast<void**>(nullptr) = nullptr;
70+
}
71+
6672
static void Chdir(const FunctionCallbackInfo<Value>& args) {
6773
Environment* env = Environment::GetCurrent(args);
6874
CHECK(env->owns_process_state());
@@ -405,6 +411,7 @@ static void InitializeProcessMethods(Local<Object> target,
405411
env->SetMethod(target, "_debugProcess", DebugProcess);
406412
env->SetMethod(target, "_debugEnd", DebugEnd);
407413
env->SetMethod(target, "abort", Abort);
414+
env->SetMethod(target, "causeSegfault", CauseSegfault);
408415
env->SetMethod(target, "chdir", Chdir);
409416
}
410417

test/abort/test-signal-handler.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
'use strict';
2+
const common = require('../common');
3+
if (common.isWindows)
4+
common.skip('No signals on Window');
5+
6+
const assert = require('assert');
7+
const { spawnSync } = require('child_process');
8+
9+
// Test that a hard crash does not cause an endless loop.
10+
11+
if (process.argv[2] === 'child') {
12+
const { internalBinding } = require('internal/test/binding');
13+
const { causeSegfault } = internalBinding('process_methods');
14+
15+
causeSegfault();
16+
} else {
17+
const child = spawnSync(process.execPath,
18+
['--expose-internals', __filename, 'child'],
19+
{ stdio: 'inherit' });
20+
// FreeBSD and macOS use SIGILL for the kind of crash we're causing here.
21+
assert(child.signal === 'SIGSEGV' || child.signal === 'SIGILL',
22+
`child.signal = ${child.signal}`);
23+
}

0 commit comments

Comments
 (0)