diff --git a/test/abort/test-addon-register-signal-handler.js b/test/abort/test-addon-register-signal-handler.js new file mode 100644 index 00000000000000..63ce4e1dbe38c5 --- /dev/null +++ b/test/abort/test-addon-register-signal-handler.js @@ -0,0 +1,7 @@ +'use strict'; +require('../common'); + +// This is a sibling test to test/addons/register-signal-handler/ + +process.env.ALLOW_CRASHES = true; +require('../addons/register-signal-handler/test'); diff --git a/test/addons/register-signal-handler/binding.cc b/test/addons/register-signal-handler/binding.cc new file mode 100644 index 00000000000000..01580578d159c4 --- /dev/null +++ b/test/addons/register-signal-handler/binding.cc @@ -0,0 +1,36 @@ +#ifndef _WIN32 +#include +#include +#include +#include +#include + +using v8::Boolean; +using v8::FunctionCallbackInfo; +using v8::Int32; +using v8::Value; + +void Handler(int signo, siginfo_t* siginfo, void* ucontext) { + char signo_char = signo; + int written; + do { + written = write(1, &signo_char, 1); // write() is signal-safe. + } while (written == -1 && errno == EINTR); + assert(written == 1); +} + +void RegisterSignalHandler(const FunctionCallbackInfo& args) { + assert(args[0]->IsInt32()); + assert(args[1]->IsBoolean()); + + int32_t signo = args[0].As()->Value(); + bool reset_handler = args[1].As()->Value(); + + node::RegisterSignalHandler(signo, Handler, reset_handler); +} + +NODE_MODULE_INIT() { + NODE_SET_METHOD(exports, "registerSignalHandler", RegisterSignalHandler); +} + +#endif // _WIN32 diff --git a/test/addons/register-signal-handler/binding.gyp b/test/addons/register-signal-handler/binding.gyp new file mode 100644 index 00000000000000..55fbe7050f18e4 --- /dev/null +++ b/test/addons/register-signal-handler/binding.gyp @@ -0,0 +1,9 @@ +{ + 'targets': [ + { + 'target_name': 'binding', + 'sources': [ 'binding.cc' ], + 'includes': ['../common.gypi'], + } + ] +} diff --git a/test/addons/register-signal-handler/test.js b/test/addons/register-signal-handler/test.js new file mode 100644 index 00000000000000..f56bb2f411024c --- /dev/null +++ b/test/addons/register-signal-handler/test.js @@ -0,0 +1,56 @@ +'use strict'; +const common = require('../../common'); +if (common.isWindows) + common.skip('No RegisterSignalHandler() on Windows'); + +const assert = require('assert'); +const fs = require('fs'); +const path = require('path'); +const { signals } = require('os').constants; +const { spawnSync } = require('child_process'); + +const bindingPath = path.resolve( + __dirname, 'build', common.buildType, 'binding.node'); + +if (!fs.existsSync(bindingPath)) + common.skip('binding not built yet'); + +const binding = require(bindingPath); + +if (process.argv[2] === 'child') { + const signo = +process.argv[3]; + const reset = process.argv[4] === 'reset'; + const count = +process.argv[5]; + + binding.registerSignalHandler(signo, reset); + for (let i = 0; i < count; i++) + process.kill(process.pid, signo); + return; +} + +for (const raiseSignal of [ 'SIGABRT', 'SIGSEGV' ]) { + const signo = signals[raiseSignal]; + for (const { reset, count, stderr, code, signal } of [ + { reset: true, count: 1, stderr: [signo], code: 0, signal: null }, + { reset: true, count: 2, stderr: [signo], code: null, signal: raiseSignal }, + { reset: false, count: 1, stderr: [signo], code: 0, signal: null }, + { reset: false, count: 2, stderr: [signo, signo], code: 0, signal: null } + ]) { + // We do not want to generate core files when running this test as an + // addon test. We require this file as an abort test as well, though, + // with ALLOW_CRASHES set. + if (signal !== null && !process.env.ALLOW_CRASHES) + continue; + // reset_handler does not work with SIGSEGV. + if (reset && signo === signals.SIGSEGV) + continue; + + const args = [__filename, 'child', signo, reset ? 'reset' : '', count]; + console.log(`Running: node ${args.join(' ')}`); + const result = spawnSync( + process.execPath, args, { stdio: ['inherit', 'pipe', 'inherit'] }); + assert.strictEqual(result.status, code); + assert.strictEqual(result.signal, signal); + assert.deepStrictEqual([...result.stdout], stderr); + } +}