Skip to content

Commit

Permalink
src: fix node watchdog race condition
Browse files Browse the repository at this point in the history
PR-URL: #43780
Fixes: #43699
Reviewed-By: Darshan Sen <[email protected]>
Reviewed-By: Antoine du Hamel <[email protected]>
  • Loading branch information
theanarkh authored and danielleadams committed Jul 26, 2022
1 parent fc843e1 commit 2493655
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/node_watchdog.cc
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ void Watchdog::Timer(uv_timer_t* timer) {
SigintWatchdog::SigintWatchdog(
v8::Isolate* isolate, bool* received_signal)
: isolate_(isolate), received_signal_(received_signal) {
Mutex::ScopedLock lock(SigintWatchdogHelper::GetInstanceActionMutex());
// Register this watchdog with the global SIGINT/Ctrl+C listener.
SigintWatchdogHelper::GetInstance()->Register(this);
// Start the helper thread, if that has not already happened.
Expand All @@ -110,6 +111,7 @@ SigintWatchdog::SigintWatchdog(


SigintWatchdog::~SigintWatchdog() {
Mutex::ScopedLock lock(SigintWatchdogHelper::GetInstanceActionMutex());
SigintWatchdogHelper::GetInstance()->Unregister(this);
SigintWatchdogHelper::GetInstance()->Stop();
}
Expand Down Expand Up @@ -144,6 +146,7 @@ void TraceSigintWatchdog::New(const FunctionCallbackInfo<Value>& args) {
void TraceSigintWatchdog::Start(const FunctionCallbackInfo<Value>& args) {
TraceSigintWatchdog* watchdog;
ASSIGN_OR_RETURN_UNWRAP(&watchdog, args.Holder());
Mutex::ScopedLock lock(SigintWatchdogHelper::GetInstanceActionMutex());
// Register this watchdog with the global SIGINT/Ctrl+C listener.
SigintWatchdogHelper::GetInstance()->Register(watchdog);
// Start the helper thread, if that has not already happened.
Expand All @@ -154,6 +157,7 @@ void TraceSigintWatchdog::Start(const FunctionCallbackInfo<Value>& args) {
void TraceSigintWatchdog::Stop(const FunctionCallbackInfo<Value>& args) {
TraceSigintWatchdog* watchdog;
ASSIGN_OR_RETURN_UNWRAP(&watchdog, args.Holder());
Mutex::ScopedLock lock(SigintWatchdogHelper::GetInstanceActionMutex());
SigintWatchdogHelper::GetInstance()->Unregister(watchdog);
SigintWatchdogHelper::GetInstance()->Stop();
}
Expand Down Expand Up @@ -215,6 +219,7 @@ void TraceSigintWatchdog::HandleInterrupt() {
signal_flag_ = SignalFlags::None;
interrupting = false;

Mutex::ScopedLock lock(SigintWatchdogHelper::GetInstanceActionMutex());
SigintWatchdogHelper::GetInstance()->Unregister(this);
SigintWatchdogHelper::GetInstance()->Stop();
raise(SIGINT);
Expand Down Expand Up @@ -413,6 +418,7 @@ SigintWatchdogHelper::~SigintWatchdogHelper() {
}

SigintWatchdogHelper SigintWatchdogHelper::instance;
Mutex SigintWatchdogHelper::instance_action_mutex_;

namespace watchdog {
static void Initialize(Local<Object> target,
Expand Down
2 changes: 2 additions & 0 deletions src/node_watchdog.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ class TraceSigintWatchdog : public HandleWrap, public SigintWatchdogBase {
class SigintWatchdogHelper {
public:
static SigintWatchdogHelper* GetInstance() { return &instance; }
static Mutex& GetInstanceActionMutex() { return instance_action_mutex_; }
void Register(SigintWatchdogBase* watchdog);
void Unregister(SigintWatchdogBase* watchdog);
bool HasPendingSignal();
Expand All @@ -123,6 +124,7 @@ class SigintWatchdogHelper {

static bool InformWatchdogsAboutSignal();
static SigintWatchdogHelper instance;
static Mutex instance_action_mutex_;

int start_stop_count_;

Expand Down
22 changes: 22 additions & 0 deletions test/parallel/test-vm-break-on-sigint.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
'use strict';
const common = require('../common');

// This test ensures that running vm with breakOnSignt option in multiple
// worker_threads does not crash.
// Issue: https://github.com/nodejs/node/issues/43699
const { Worker } = require('worker_threads');
const vm = require('vm');

// Don't use isMainThread to allow running this test inside a worker.
if (!process.env.HAS_STARTED_WORKER) {
process.env.HAS_STARTED_WORKER = 1;
for (let i = 0; i < 10; i++) {
const worker = new Worker(__filename);
worker.on('exit', common.mustCall());
}
} else {
const ctx = vm.createContext({});
for (let i = 0; i < 10000; i++) {
vm.runInContext('console.log(1)', ctx, { breakOnSigint: true });
}
}

0 comments on commit 2493655

Please sign in to comment.