diff options
author | 2023-07-18 23:09:39 -0700 | |
---|---|---|
committer | 2023-07-18 23:09:39 -0700 | |
commit | a59ddb131eab3dbfaf193c11b230c0e4709b3b66 (patch) | |
tree | a7e42b48eca442e12a1e206e904c24a5fcf82617 | |
parent | 8bd2b784a272f4ee571cbc924f8822d7ba6f7b51 (diff) | |
download | bun-a59ddb131eab3dbfaf193c11b230c0e4709b3b66.tar.gz bun-a59ddb131eab3dbfaf193c11b230c0e4709b3b66.tar.zst bun-a59ddb131eab3dbfaf193c11b230c0e4709b3b66.zip |
Fix crash in postMessage that repro'd after ~100,000 messages
-rw-r--r-- | src/bun.js/bindings/ScriptExecutionContext.cpp | 3 | ||||
-rw-r--r-- | src/bun.js/bindings/webcore/JSWorker.cpp | 8 | ||||
-rw-r--r-- | src/bun.js/bindings/webcore/Worker.cpp | 14 | ||||
-rw-r--r-- | src/bun.js/bindings/webcore/Worker.h | 1 | ||||
-rw-r--r-- | src/bun.js/module_loader.zig | 6 | ||||
-rw-r--r-- | src/bun.js/web_worker.zig | 46 |
6 files changed, 57 insertions, 21 deletions
diff --git a/src/bun.js/bindings/ScriptExecutionContext.cpp b/src/bun.js/bindings/ScriptExecutionContext.cpp index f878fd9fb..d93478ed8 100644 --- a/src/bun.js/bindings/ScriptExecutionContext.cpp +++ b/src/bun.js/bindings/ScriptExecutionContext.cpp @@ -120,8 +120,7 @@ void ScriptExecutionContext::regenerateIdentifier() m_identifier = ++lastUniqueIdentifier; - Locker locker { allScriptExecutionContextsMapLock }; - allScriptExecutionContextsMap().add(m_identifier, this); + addToContextsMap(); } void ScriptExecutionContext::addToContextsMap() diff --git a/src/bun.js/bindings/webcore/JSWorker.cpp b/src/bun.js/bindings/webcore/JSWorker.cpp index 68e06a2a0..bcf670d63 100644 --- a/src/bun.js/bindings/webcore/JSWorker.cpp +++ b/src/bun.js/bindings/webcore/JSWorker.cpp @@ -162,8 +162,16 @@ template<> EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSWorkerDOMConstructor::const auto jsValue = toJSNewlyCreated<IDLInterface<Worker>>(*lexicalGlobalObject, *castedThis->globalObject(), throwScope, WTFMove(object)); if constexpr (IsExceptionOr<decltype(object)>) RETURN_IF_EXCEPTION(throwScope, {}); + + auto& impl = jsCast<JSWorker*>(jsValue)->wrapped(); + if (!impl.updatePtr()) { + throwVMError(lexicalGlobalObject, throwScope, "Failed to start Worker thread"_s); + return encodedJSValue(); + } + setSubclassStructureIfNeeded<Worker>(lexicalGlobalObject, callFrame, asObject(jsValue)); RETURN_IF_EXCEPTION(throwScope, {}); + return JSValue::encode(jsValue); } JSC_ANNOTATE_HOST_FUNCTION(JSWorkerDOMConstructorConstruct, JSWorkerDOMConstructor::construct); diff --git a/src/bun.js/bindings/webcore/Worker.cpp b/src/bun.js/bindings/webcore/Worker.cpp index d92b6e2e5..dfbc0e007 100644 --- a/src/bun.js/bindings/webcore/Worker.cpp +++ b/src/bun.js/bindings/webcore/Worker.cpp @@ -105,7 +105,7 @@ Worker::Worker(ScriptExecutionContext& context, WorkerOptions&& options) auto addResult = allWorkers().add(m_clientIdentifier, this); ASSERT_UNUSED(addResult, addResult.isNewEntry); } - +extern "C" bool WebWorker__updatePtr(void* worker, Worker* ptr); extern "C" void* WebWorker__create( Worker* worker, void* parent, @@ -125,6 +125,18 @@ void Worker::setKeepAlive(bool keepAlive) WebWorker__setRef(impl_, keepAlive); } +bool Worker::updatePtr() +{ + if (!WebWorker__updatePtr(impl_, this)) { + m_wasTerminated = true; + m_isClosing = true; + m_isOnline = false; + return false; + } + + return true; +} + ExceptionOr<Ref<Worker>> Worker::create(ScriptExecutionContext& context, const String& urlInit, WorkerOptions&& options) { auto worker = adoptRef(*new Worker(context, WTFMove(options))); diff --git a/src/bun.js/bindings/webcore/Worker.h b/src/bun.js/bindings/webcore/Worker.h index 99a54e37f..b0b8e0a2b 100644 --- a/src/bun.js/bindings/webcore/Worker.h +++ b/src/bun.js/bindings/webcore/Worker.h @@ -70,6 +70,7 @@ public: void terminate(); bool wasTerminated() const { return m_wasTerminated; } bool hasPendingActivity() const; + bool updatePtr(); String identifier() const { return m_identifier; } const String& name() const { return m_options.name; } diff --git a/src/bun.js/module_loader.zig b/src/bun.js/module_loader.zig index 483ff94cb..6a04540b1 100644 --- a/src/bun.js/module_loader.zig +++ b/src/bun.js/module_loader.zig @@ -1697,6 +1697,12 @@ pub const ModuleLoader = struct { // so it consistently handles bundled imports // we can't take the shortcut of just directly importing the file, sadly. .@"bun:main" => { + defer { + if (jsc_vm.worker) |worker| { + worker.queueInitialTask(); + } + } + if (comptime disable_transpilying) { return ResolvedSource{ .allocator = null, diff --git a/src/bun.js/web_worker.zig b/src/bun.js/web_worker.zig index df2e63c3a..39ab2c8f1 100644 --- a/src/bun.js/web_worker.zig +++ b/src/bun.js/web_worker.zig @@ -19,20 +19,39 @@ pub const WebWorker = struct { store_fd: bool = false, arena: bun.MimallocArena = undefined, name: [:0]const u8 = "Worker", - cpp_worker: *void, + cpp_worker: *anyopaque, allowed_to_exit: bool = false, mini: bool = false, parent_poll_ref: JSC.PollRef = .{}, initial_poll_ref: JSC.PollRef = .{}, + did_send_initial_task: bool = false, - extern fn WebWorker__dispatchExit(?*JSC.JSGlobalObject, *void, i32) void; - extern fn WebWorker__dispatchOnline(this: *void, *JSC.JSGlobalObject) void; - extern fn WebWorker__dispatchError(*JSC.JSGlobalObject, *void, bun.String, JSValue) void; + extern fn WebWorker__dispatchExit(?*JSC.JSGlobalObject, *anyopaque, i32) void; + extern fn WebWorker__dispatchOnline(this: *anyopaque, *JSC.JSGlobalObject) void; + extern fn WebWorker__dispatchError(*JSC.JSGlobalObject, *anyopaque, bun.String, JSValue) void; export fn WebWorker__getParentWorker(vm: *JSC.VirtualMachine) ?*anyopaque { var worker = vm.worker orelse return null; return worker.cpp_worker; } + export fn WebWorker__updatePtr(worker: *WebWorker, ptr: *anyopaque) bool { + worker.cpp_worker = ptr; + + var thread = std.Thread.spawn( + .{ .stack_size = 2 * 1024 * 1024 }, + startWithErrorHandling, + .{worker}, + ) catch { + worker.deinit(); + worker.parent_poll_ref.unref(worker.parent); + worker.initial_poll_ref.unref(worker.parent); + bun.default_allocator.destroy(worker); + return false; + }; + thread.detach(); + return true; + } + pub fn hasPendingActivity(this: *WebWorker) callconv(.C) bool { JSC.markBinding(@src()); @@ -105,23 +124,13 @@ pub const WebWorker = struct { worker.parent_poll_ref.ref(parent); } - var thread = std.Thread.spawn( - .{ .stack_size = 2 * 1024 * 1024 }, - startWithErrorHandling, - .{worker}, - ) catch { - worker.deinit(); - worker.requested_terminate = true; - worker.parent_poll_ref.unref(worker.parent); - worker.initial_poll_ref.unref(worker.parent); - return null; - }; - thread.detach(); - return worker; } - fn queueInitialTask(this: *WebWorker) void { + pub fn queueInitialTask(this: *WebWorker) void { + if (this.did_send_initial_task) return; + this.did_send_initial_task = true; + const Unref = struct { pub fn unref(worker: *WebWorker) void { worker.initial_poll_ref.unref(worker.parent); @@ -364,6 +373,7 @@ pub const WebWorker = struct { @export(create, .{ .name = "WebWorker__create" }); @export(terminate, .{ .name = "WebWorker__terminate" }); @export(setRef, .{ .name = "WebWorker__setRef" }); + _ = WebWorker__updatePtr; } } |