fix: crash on WebWorkerObserver script execution (#37050)

fix: crash on WebWorkerObserver script execution
This commit is contained in:
Shelley Vohr 2023-01-31 12:29:29 +01:00 committed by GitHub
parent ce35bda805
commit 23739c644b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 109 additions and 16 deletions

View file

@ -168,7 +168,12 @@ void ElectronRendererClient::WorkerScriptReadyForEvaluationOnWorkerThread(
// that have a different value for nodeIntegrationInWorker
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kNodeIntegrationInWorker)) {
WebWorkerObserver::GetCurrent()->WorkerScriptReadyForEvaluation(context);
// WorkerScriptReadyForEvaluationOnWorkerThread can be invoked multiple
// times for the same thread, so we need to create a new observer each time
// this happens. We use a ThreadLocalOwnedPointer to ensure that the old
// observer for a given thread gets destructed when swapping with the new
// observer in WebWorkerObserver::Create.
WebWorkerObserver::Create()->WorkerScriptReadyForEvaluation(context);
}
}
@ -182,7 +187,9 @@ void ElectronRendererClient::WillDestroyWorkerContextOnWorkerThread(
// with webPreferences that have a different value for nodeIntegrationInWorker
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kNodeIntegrationInWorker)) {
WebWorkerObserver::GetCurrent()->ContextWillDestroy(context);
auto* current = WebWorkerObserver::GetCurrent();
if (current)
current->ContextWillDestroy(context);
}
}

View file

@ -4,7 +4,9 @@
#include "shell/renderer/web_worker_observer.h"
#include "base/lazy_instance.h"
#include <utility>
#include "base/no_destructor.h"
#include "base/threading/thread_local.h"
#include "shell/common/api/electron_bindings.h"
#include "shell/common/gin_helper/event_emitter_caller.h"
@ -15,28 +17,31 @@ namespace electron {
namespace {
static base::LazyInstance<
base::ThreadLocalPointer<WebWorkerObserver>>::DestructorAtExit lazy_tls =
LAZY_INSTANCE_INITIALIZER;
static base::NoDestructor<base::ThreadLocalOwnedPointer<WebWorkerObserver>>
lazy_tls;
} // namespace
// static
WebWorkerObserver* WebWorkerObserver::GetCurrent() {
WebWorkerObserver* self = lazy_tls.Pointer()->Get();
return self ? self : new WebWorkerObserver;
return lazy_tls->Get();
}
// static
WebWorkerObserver* WebWorkerObserver::Create() {
auto obs = std::make_unique<WebWorkerObserver>();
auto* obs_raw = obs.get();
lazy_tls->Set(std::move(obs));
return obs_raw;
}
WebWorkerObserver::WebWorkerObserver()
: node_bindings_(
NodeBindings::Create(NodeBindings::BrowserEnvironment::kWorker)),
electron_bindings_(
std::make_unique<ElectronBindings>(node_bindings_->uv_loop())) {
lazy_tls.Pointer()->Set(this);
}
std::make_unique<ElectronBindings>(node_bindings_->uv_loop())) {}
WebWorkerObserver::~WebWorkerObserver() {
lazy_tls.Pointer()->Set(nullptr);
// Destroying the node environment will also run the uv loop,
// Node.js expects `kExplicit` microtasks policy and will run microtasks
// checkpoints after every call into JavaScript. Since we use a different
@ -90,7 +95,8 @@ void WebWorkerObserver::ContextWillDestroy(v8::Local<v8::Context> context) {
if (env)
gin_helper::EmitEvent(env->isolate(), env->process_object(), "exit");
delete this;
if (lazy_tls->Get())
lazy_tls->Set(nullptr);
}
} // namespace electron

View file

@ -17,8 +17,13 @@ class NodeBindings;
// Watches for WebWorker and insert node integration to it.
class WebWorkerObserver {
public:
WebWorkerObserver();
~WebWorkerObserver();
// Returns the WebWorkerObserver for current worker thread.
static WebWorkerObserver* GetCurrent();
// Creates a new WebWorkerObserver for a given context.
static WebWorkerObserver* Create();
// disable copy
WebWorkerObserver(const WebWorkerObserver&) = delete;
@ -28,9 +33,6 @@ class WebWorkerObserver {
void ContextWillDestroy(v8::Local<v8::Context> context);
private:
WebWorkerObserver();
~WebWorkerObserver();
std::unique_ptr<NodeBindings> node_bindings_;
std::unique_ptr<ElectronBindings> electron_bindings_;
};