From 16b2bc18336ab3495c65b5feaef35461d540cfd5 Mon Sep 17 00:00:00 2001 From: Marcel Laverdet Date: Tue, 3 May 2022 10:25:45 -0500 Subject: [PATCH] Fix deadlock from disposal under certain circumstances Fixes #302 --- src/isolate/scheduler.cc | 14 +++++++------- src/isolate/scheduler.h | 12 ++++++++++-- tests/self-async-dispose.js | 9 +++++++++ 3 files changed, 26 insertions(+), 9 deletions(-) create mode 100644 tests/self-async-dispose.js diff --git a/src/isolate/scheduler.cc b/src/isolate/scheduler.cc index 51406a4..aebea70 100644 --- a/src/isolate/scheduler.cc +++ b/src/isolate/scheduler.cc @@ -171,24 +171,24 @@ Scheduler::AsyncWait::~AsyncWait() { } void Scheduler::AsyncWait::Ready() { - auto lock = scheduler.Lock(); - ready = true; - if (done) { + auto lock = state.write(); + lock->ready = true; + if (lock->done) { scheduler.cv.notify_one(); } } void Scheduler::AsyncWait::Wait() { std::unique_lock lock{scheduler.mutex}; - while (!ready || !done) { + while (!state.read()->did_initialize()) { scheduler.cv.wait(lock); } } void Scheduler::AsyncWait::Wake() { - auto lock = scheduler.Lock(); - done = true; - if (ready) { + auto lock = state.write(); + lock->done = true; + if (lock->ready) { scheduler.cv.notify_one(); } } diff --git a/src/isolate/scheduler.h b/src/isolate/scheduler.h index 9ed2748..d9a76fb 100644 --- a/src/isolate/scheduler.h +++ b/src/isolate/scheduler.h @@ -68,9 +68,17 @@ class Scheduler { void Wake(); private: + struct state_t { + bool ready = false; + bool done = false; + + bool did_initialize() const { + return ready || done; + } + }; + class LockedScheduler& scheduler; - bool done = false; - bool ready = false; + lockable_t state; }; // Task queues diff --git a/tests/self-async-dispose.js b/tests/self-async-dispose.js new file mode 100644 index 0000000..587d150 --- /dev/null +++ b/tests/self-async-dispose.js @@ -0,0 +1,9 @@ +const ivm = require('isolated-vm'); + +const isolate = new ivm.Isolate(); +const context = isolate.createContextSync(); +context.global.setSync("getProm", () => {}, { reference: true }); +context.eval("getProm.applySync()").catch(() => console.log('pass')); +context.release(); +process.nextTick(() => {}); +isolate.dispose();