diff --git a/src/bun.js/event_loop.zig b/src/bun.js/event_loop.zig index a04e7e53c2..a5ff5764cd 100644 --- a/src/bun.js/event_loop.zig +++ b/src/bun.js/event_loop.zig @@ -321,7 +321,7 @@ pub fn tickConcurrentWithCount(this: *EventLoop) usize { dest.deinit(); } - if (task.next.autoDelete()) { + if (task.auto_delete()) { to_destroy = task; } diff --git a/src/bun.js/event_loop/ConcurrentTask.zig b/src/bun.js/event_loop/ConcurrentTask.zig index 071df3143f..d6398bdb8f 100644 --- a/src/bun.js/event_loop/ConcurrentTask.zig +++ b/src/bun.js/event_loop/ConcurrentTask.zig @@ -44,7 +44,8 @@ pub const PackedNext = packed struct(u64) { pub fn get(self: PackedNext) ?*ConcurrentTask { if (self.ptr_bits == 0) return null; - const ptr: u64 = @as(u64, self.ptr_bits); + // Explicitly zero out bit 63 to avoid any UB + const ptr: u64 = @as(u64, self.ptr_bits) & 0x7FFFFFFFFFFFFFFF; return @as(?*ConcurrentTask, @ptrFromInt(ptr)); } @@ -69,6 +70,12 @@ pub const Queue = bun.threading.UnboundedQueuePacked(ConcurrentTask, .next, .@"p pub const new = bun.TrivialNew(@This()); pub const deinit = bun.TrivialDeinit(@This()); +/// Returns whether this task should be automatically deleted after completion. +/// The auto_delete flag being stored in the next field is an implementation detail. +pub inline fn auto_delete(this: *const ConcurrentTask) bool { + return this.next.autoDelete(); +} + pub const AutoDeinit = enum { manual_deinit, auto_deinit,