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: https://github.com/nodejs/node/pull/27775
Refs: https://github.com/nodejs/node/pull/27246
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
This commit is contained in:
Anna Henningsen 2019-05-20 01:57:17 +02:00
parent e6b3ec3d3c
commit e256204776
No known key found for this signature in database
GPG Key ID: 9C63F3A6CD2AD8F9
3 changed files with 36 additions and 0 deletions

View File

@ -487,6 +487,12 @@ void TrapWebAssemblyOrContinue(int signo, siginfo_t* info, void* ucontext) {
if (prev != nullptr) {
prev(signo, info, ucontext);
} else {
// Reset to the default signal handler, i.e. cause a hard crash.
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = SIG_DFL;
CHECK_EQ(sigaction(signo, &sa, nullptr), 0);
ResetStdio();
raise(signo);
}

View File

@ -63,6 +63,12 @@ static void Abort(const FunctionCallbackInfo<Value>& args) {
Abort();
}
// For internal testing only, not exposed to userland.
static void CauseSegfault(const FunctionCallbackInfo<Value>& args) {
// This should crash hard all platforms.
*static_cast<void**>(nullptr) = nullptr;
}
static void Chdir(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
CHECK(env->owns_process_state());
@ -405,6 +411,7 @@ static void InitializeProcessMethods(Local<Object> target,
env->SetMethod(target, "_debugProcess", DebugProcess);
env->SetMethod(target, "_debugEnd", DebugEnd);
env->SetMethod(target, "abort", Abort);
env->SetMethod(target, "causeSegfault", CauseSegfault);
env->SetMethod(target, "chdir", Chdir);
}

View File

@ -0,0 +1,23 @@
'use strict';
const common = require('../common');
if (common.isWindows)
common.skip('No signals on Window');
const assert = require('assert');
const { spawnSync } = require('child_process');
// Test that a hard crash does not cause an endless loop.
if (process.argv[2] === 'child') {
const { internalBinding } = require('internal/test/binding');
const { causeSegfault } = internalBinding('process_methods');
causeSegfault();
} else {
const child = spawnSync(process.execPath,
['--expose-internals', __filename, 'child'],
{ stdio: 'inherit' });
// FreeBSD and macOS use SIGILL for the kind of crash we're causing here.
assert(child.signal === 'SIGSEGV' || child.signal === 'SIGILL',
`child.signal = ${child.signal}`);
}