From 831ae976e8fe5f25f2d52a499ca23df03300b78e Mon Sep 17 00:00:00 2001 From: Meghan Denny Date: Thu, 16 Oct 2025 22:26:47 -0700 Subject: [PATCH] node tests --- src/bun.js/api/crypto.classes.ts | 2 +- src/bun.js/bindgen.zig | 4 +--- src/bun.js/event_loop/JSCScheduler.zig | 6 ++--- src/bun.js/event_loop/Task.zig | 2 +- src/bun.js/node/path_watcher.zig | 3 +-- src/bun.js/webcore/Blob.zig | 1 + src/bun.js/webcore/Crypto.zig | 4 ++++ src/bun.js/webcore/streams.zig | 2 +- src/bun.zig | 12 +++++----- src/codegen/generate-classes.ts | 32 +++++++++++++------------- src/sys/PosixStat.zig | 2 +- test/leaksan.supp | 2 +- test/no-validate-leaksan.txt | 1 + 13 files changed, 38 insertions(+), 35 deletions(-) diff --git a/src/bun.js/api/crypto.classes.ts b/src/bun.js/api/crypto.classes.ts index 9f64ec1f0e..b3b2c1e467 100644 --- a/src/bun.js/api/crypto.classes.ts +++ b/src/bun.js/api/crypto.classes.ts @@ -37,7 +37,7 @@ export default [ define({ name: "Crypto", construct: true, - finalize: false, + finalize: true, proto: { getRandomValues: { diff --git a/src/bun.js/bindgen.zig b/src/bun.js/bindgen.zig index be303cb6ff..3fbfa75ca8 100644 --- a/src/bun.js/bindgen.zig +++ b/src/bun.js/bindgen.zig @@ -207,9 +207,7 @@ pub fn BindgenArray(comptime Child: type) type { return .fromUnmanaged(.{}, new_unmanaged); } - defer unmanaged.deinit( - if (bun.use_mimalloc) bun.default_allocator else std.heap.raw_c_allocator, - ); + defer if (bun.use_mimalloc) unmanaged.deinit(bun.default_allocator); var result = bun.handleOom(ZigType.initCapacity(length)); for (unmanaged.items) |*item| { result.appendAssumeCapacity(Child.convertFromExtern(item.*)); diff --git a/src/bun.js/event_loop/JSCScheduler.zig b/src/bun.js/event_loop/JSCScheduler.zig index dbce749657..ea1ef406cb 100644 --- a/src/bun.js/event_loop/JSCScheduler.zig +++ b/src/bun.js/event_loop/JSCScheduler.zig @@ -2,13 +2,13 @@ const JSCScheduler = @This(); pub const JSCDeferredWorkTask = opaque { extern fn Bun__runDeferredWork(task: *JSCScheduler.JSCDeferredWorkTask) void; - pub fn run(task: *JSCScheduler.JSCDeferredWorkTask) bun.JSTerminated!void { + pub fn run(task: *JSCScheduler.JSCDeferredWorkTask) bun.JSError!void { const globalThis = bun.jsc.VirtualMachine.get().global; - var scope: bun.jsc.ExceptionValidationScope = undefined; + var scope: bun.jsc.CatchScope = undefined; scope.init(globalThis, @src()); defer scope.deinit(); Bun__runDeferredWork(task); - try scope.assertNoExceptionExceptTermination(); + try scope.returnIfException(); } }; diff --git a/src/bun.js/event_loop/Task.zig b/src/bun.js/event_loop/Task.zig index 58cc3a6129..d022691620 100644 --- a/src/bun.js/event_loop/Task.zig +++ b/src/bun.js/event_loop/Task.zig @@ -237,7 +237,7 @@ pub fn tickQueueWithCount(this: *EventLoop, virtual_machine: *VirtualMachine, co @field(Task.Tag, @typeName(JSCDeferredWorkTask)) => { var jsc_task: *JSCDeferredWorkTask = task.get(JSCDeferredWorkTask).?; jsc.markBinding(@src()); - try jsc_task.run(); + jsc_task.run() catch |err| try reportErrorOrTerminate(global, err); }, @field(Task.Tag, @typeName(WriteFileTask)) => { var transform_task: *WriteFileTask = task.get(WriteFileTask).?; diff --git a/src/bun.js/node/path_watcher.zig b/src/bun.js/node/path_watcher.zig index 16c1f5b462..60032a771a 100644 --- a/src/bun.js/node/path_watcher.zig +++ b/src/bun.js/node/path_watcher.zig @@ -746,7 +746,6 @@ pub const PathWatcher = struct { bun.default_allocator.destroy(this); return err; }; - this.resolved_path = resolved_path; this.* = PathWatcher{ .path = path, .callback = callback, @@ -766,8 +765,8 @@ pub const PathWatcher = struct { .file_paths = .{}, .ctx = ctx, .mutex = .{}, + .resolved_path = resolved_path, }; - errdefer this.deinit(); // TODO: unify better FSEvents with PathWatcherManager diff --git a/src/bun.js/webcore/Blob.zig b/src/bun.js/webcore/Blob.zig index 1827b9faf4..bf59944c00 100644 --- a/src/bun.js/webcore/Blob.zig +++ b/src/bun.js/webcore/Blob.zig @@ -4789,6 +4789,7 @@ export fn Blob__ref(self: *Blob) void { export fn Blob__deref(self: *Blob) void { bun.assertf(self.isHeapAllocated(), "cannot deref: this Blob is not heap-allocated", .{}); if (self.#ref_count.decrement() == .should_destroy) { + self.#ref_count.increment(); // deinit has its own isHeapAllocated() guard around bun.destroy(this), so this is needed to ensure that returns true. self.deinit(); } } diff --git a/src/bun.js/webcore/Crypto.zig b/src/bun.js/webcore/Crypto.zig index 653b9a17be..6dbdab8f83 100644 --- a/src/bun.js/webcore/Crypto.zig +++ b/src/bun.js/webcore/Crypto.zig @@ -277,6 +277,10 @@ pub export fn CryptoObject__create(globalThis: *jsc.JSGlobalObject) jsc.JSValue return ptr.toJS(globalThis); } +pub fn finalize(this: *Crypto) void { + bun.default_allocator.destroy(this); +} + const std = @import("std"); const UUID = @import("../uuid.zig"); diff --git a/src/bun.js/webcore/streams.zig b/src/bun.js/webcore/streams.zig index 2b3bd89bb3..db020fde0e 100644 --- a/src/bun.js/webcore/streams.zig +++ b/src/bun.js/webcore/streams.zig @@ -556,7 +556,7 @@ pub const Result = union(Tag) { if (jsc.VirtualMachine.get().isShuttingDown()) { var that = this.*; that.deinit(); - return .zero; + return .js_undefined; } switch (this.*) { diff --git a/src/bun.zig b/src/bun.zig index 39f671a826..09c7f8879c 100644 --- a/src/bun.zig +++ b/src/bun.zig @@ -29,8 +29,8 @@ pub fn default_malloc_usable_size(p: ?*const anyopaque) usize { }; } -pub const callmod_inline: std.builtin.CallModifier = if (builtin.mode == .Debug) .auto else .always_inline; -pub const callconv_inline: std.builtin.CallingConvention = if (builtin.mode == .Debug) .Unspecified else .Inline; +pub const callmod_inline: std.builtin.CallModifier = if (builtin.mode == .Debug or Environment.enable_asan) .auto else .always_inline; +pub const callconv_inline: std.builtin.CallingConvention = if (builtin.mode == .Debug or Environment.enable_asan) .Unspecified else .Inline; /// In debug builds, this will catch memory leaks. In release builds, it is mimalloc. pub const debug_allocator: std.mem.Allocator = if (Environment.isDebug or Environment.enable_asan) @@ -2691,12 +2691,12 @@ pub const heap_breakdown = @import("./heap_breakdown.zig"); /// - Additional assertions when freeing memory. /// /// On macOS, you can use `Bun.unsafe.mimallocDump()` to dump the heap. -pub inline fn new(comptime T: type, init: T) *T { +pub fn new(comptime T: type, init: T) *T { return handleOom(tryNew(T, init)); } /// Error-returning version of `new`. -pub inline fn tryNew(comptime T: type, init: T) OOM!*T { +pub fn tryNew(comptime T: type, init: T) OOM!*T { const pointer = if (heap_breakdown.enabled) try heap_breakdown.getZoneT(T).tryCreate(T, init) else pointer: { @@ -2718,7 +2718,7 @@ pub inline fn tryNew(comptime T: type, init: T) OOM!*T { /// Destruction performs additional safety checks: /// - Generic assertions can be added to T.assertBeforeDestroy() /// - Automatic integration with `RefCount` -pub inline fn destroy(pointer: anytype) void { +pub fn destroy(pointer: anytype) void { const T = std.meta.Child(@TypeOf(pointer)); if (Environment.allow_assert) { @@ -2740,7 +2740,7 @@ pub inline fn destroy(pointer: anytype) void { } } -pub inline fn dupe(comptime T: type, t: *T) *T { +pub fn dupe(comptime T: type, t: *T) *T { return new(T, t.*); } diff --git a/src/codegen/generate-classes.ts b/src/codegen/generate-classes.ts index a5622f8e60..d24dea6953 100644 --- a/src/codegen/generate-classes.ts +++ b/src/codegen/generate-classes.ts @@ -2170,7 +2170,7 @@ const JavaScriptCoreBindings = struct { output += ` pub fn ${classSymbolName(typeName, "finalize")}(thisValue: *${typeName}) callconv(jsc.conv) void { if (comptime Environment.enable_logs) log_zig_finalize("${typeName}", thisValue); - @call(.always_inline, ${typeName}.finalize, .{thisValue}); + @call(bun.callmod_inline, ${typeName}.finalize, .{thisValue}); } `; } @@ -2213,7 +2213,7 @@ const JavaScriptCoreBindings = struct { output += ` pub fn ${classSymbolName(typeName, "call")}(globalObject: *jsc.JSGlobalObject, callFrame: *jsc.CallFrame) callconv(jsc.conv) jsc.JSValue { if (comptime Environment.enable_logs) log_zig_call("${typeName}", callFrame); - return @call(.always_inline, jsc.toJSHostFn(${typeName}.call), .{globalObject, callFrame}); + return @call(bun.callmod_inline, jsc.toJSHostFn(${typeName}.call), .{globalObject, callFrame}); } `; } @@ -2223,7 +2223,7 @@ const JavaScriptCoreBindings = struct { output += ` pub fn ${classSymbolName(typeName, "getInternalProperties")}(thisValue: *${typeName}, globalObject: *jsc.JSGlobalObject, thisValue: jsc.JSValue) callconv(jsc.conv) jsc.JSValue { if (comptime Environment.enable_logs) log_zig_get_internal_properties("${typeName}"); - return @call(.always_inline, ${typeName}.getInternalProperties, .{thisValue, globalObject, thisValue}); + return @call(bun.callmod_inline, ${typeName}.getInternalProperties, .{thisValue, globalObject, thisValue}); } `; } @@ -2239,9 +2239,9 @@ const JavaScriptCoreBindings = struct { if (comptime Environment.enable_logs) log_zig_getter("${typeName}", "${name}"); return switch (@typeInfo(@typeInfo(@TypeOf(${typeName}.${getter})).@"fn".return_type.?)) { .error_union => { - return @call(.always_inline, jsc.toJSHostCall, .{globalObject, @src(), ${typeName}.${getter}, .{this, ${thisValue ? "thisValue," : ""} globalObject}}); + return @call(bun.callmod_inline, jsc.toJSHostCall, .{globalObject, @src(), ${typeName}.${getter}, .{this, ${thisValue ? "thisValue," : ""} globalObject}}); }, - else => @call(.always_inline, ${typeName}.${getter}, .{this, ${thisValue ? "thisValue," : ""} globalObject}), + else => @call(bun.callmod_inline, ${typeName}.${getter}, .{this, ${thisValue ? "thisValue," : ""} globalObject}), }; } `; @@ -2256,10 +2256,10 @@ const JavaScriptCoreBindings = struct { if (error_union.payload != void) { @compileError("Setter return type must be JSError!void or void"); } - return @call(.always_inline, jsc.host_fn.toJSHostSetterValue, .{globalObject, @call(.always_inline, ${typeName}.${setter}, .{this, ${thisValue ? "thisValue," : ""} globalObject, value})}); + return @call(bun.callmod_inline, jsc.host_fn.toJSHostSetterValue, .{globalObject, @call(bun.callmod_inline, ${typeName}.${setter}, .{this, ${thisValue ? "thisValue," : ""} globalObject, value})}); }, .void => { - @call(.always_inline, ${typeName}.${setter}, .{this, ${thisValue ? "thisValue," : ""} globalObject, value}); + @call(bun.callmod_inline, ${typeName}.${setter}, .{this, ${thisValue ? "thisValue," : ""} globalObject, value}); return true; }, else => @compileError("Setter return type must be JSError!void or void"), @@ -2283,7 +2283,7 @@ const JavaScriptCoreBindings = struct { output += ` pub fn ${names.fn}(thisValue: *${typeName}, globalObject: *jsc.JSGlobalObject, callFrame: *jsc.CallFrame${proto[name].passThis ? ", js_this_value: jsc.JSValue" : ""}) callconv(jsc.conv) jsc.JSValue { if (comptime Environment.enable_logs) log_zig_method("${typeName}", "${name}", callFrame); - return @call(.always_inline, jsc.toJSHostCall, .{globalObject, @src(), ${typeName}.${fn}, .{thisValue, globalObject, callFrame${proto[name].passThis ? ", js_this_value" : ""}}}); + return @call(bun.callmod_inline, jsc.toJSHostCall, .{globalObject, @src(), ${typeName}.${fn}, .{thisValue, globalObject, callFrame${proto[name].passThis ? ", js_this_value" : ""}}}); } `; } @@ -2301,10 +2301,10 @@ const JavaScriptCoreBindings = struct { if (comptime Environment.enable_logs) log_zig_class_getter("${typeName}", "${name}"); return switch (@typeInfo(@typeInfo(@TypeOf(${typeName}.${getter})).@"fn".return_type.?)) { .error_union => { - return @call(.always_inline, jsc.toJSHostCall, .{globalObject, @src(), ${typeName}.${getter}, .{globalObject, ${thisValue ? "thisValue," : ""} propertyName}}); + return @call(bun.callmod_inline, jsc.toJSHostCall, .{globalObject, @src(), ${typeName}.${getter}, .{globalObject, ${thisValue ? "thisValue," : ""} propertyName}}); }, else => { - return @call(.always_inline, ${typeName}.${getter}, .{globalObject, ${thisValue ? "thisValue," : ""} propertyName}); + return @call(bun.callmod_inline, ${typeName}.${getter}, .{globalObject, ${thisValue ? "thisValue," : ""} propertyName}); }, }; } @@ -2315,7 +2315,7 @@ const JavaScriptCoreBindings = struct { output += ` pub fn ${names.setter}(globalObject: *jsc.JSGlobalObject, thisValue: jsc.JSValue, target: jsc.JSValue) callconv(jsc.conv) bool { if (comptime Environment.enable_logs) log_zig_class_setter("${typeName}", "${name}", target); - return @call(.always_inline, ${typeName}.${setter || accessor.setter}, .{thisValue, globalObject, target}); + return @call(bun.callmod_inline, ${typeName}.${setter || accessor.setter}, .{thisValue, globalObject, target}); } `; } @@ -2329,7 +2329,7 @@ const JavaScriptCoreBindings = struct { .map(ZigDOMJITArgTypeDefinition) .join(", ")}) callconv(jsc.conv) jsc.JSValue { if (comptime Environment.enable_logs) log_zig_class_domjit("${typeName}", "${name}"); - return @call(.always_inline, ${typeName}.${DOMJITName(fn)}, .{thisValue, globalObject, ${args.map((_, i) => `arg${i}`).join(", ")}}); + return @call(bun.callmod_inline, ${typeName}.${DOMJITName(fn)}, .{thisValue, globalObject, ${args.map((_, i) => `arg${i}`).join(", ")}}); } `; } @@ -2337,7 +2337,7 @@ const JavaScriptCoreBindings = struct { output += ` pub fn ${names.fn}(globalObject: *jsc.JSGlobalObject, callFrame: *jsc.CallFrame) callconv(jsc.conv) jsc.JSValue { if (comptime Environment.enable_logs) log_zig_class_method("${typeName}", "${name}", callFrame); - return @call(.always_inline, jsc.toJSHostFn(${typeName}.${fn}), .{globalObject, callFrame}); + return @call(bun.callmod_inline, jsc.toJSHostFn(${typeName}.${fn}), .{globalObject, callFrame}); } `; } @@ -2349,7 +2349,7 @@ const JavaScriptCoreBindings = struct { output += ` pub fn ${symbolName(typeName, "onStructuredCloneSerialize")}(thisValue: *${typeName}, globalObject: *jsc.JSGlobalObject, ctx: *anyopaque, writeBytes: WriteBytesFn) callconv(jsc.conv) void { if (comptime Environment.enable_logs) log_zig_structured_clone_serialize("${typeName}"); - @call(.always_inline, ${typeName}.onStructuredCloneSerialize, .{thisValue, globalObject, ctx, writeBytes}); + @call(bun.callmod_inline, ${typeName}.onStructuredCloneSerialize, .{thisValue, globalObject, ctx, writeBytes}); } `; @@ -2358,7 +2358,7 @@ const JavaScriptCoreBindings = struct { output += ` pub fn ${exports.get("structuredClone_transferable")}(thisValue: *${typeName}, globalObject: *jsc.JSGlobalObject, ctx: *anyopaque, write: WriteBytesFn) callconv(jsc.conv) void { if (comptime Environment.enable_logs) log_zig_structured_clone_transfer("${typeName}"); - @call(.always_inline, ${typeName}.onStructuredCloneTransfer, .{thisValue, globalObject, ctx, write}); + @call(bun.callmod_inline, ${typeName}.onStructuredCloneTransfer, .{thisValue, globalObject, ctx, write}); } `; } @@ -2368,7 +2368,7 @@ const JavaScriptCoreBindings = struct { output += ` pub fn ${symbolName(typeName, "onStructuredCloneDeserialize")}(globalObject: *jsc.JSGlobalObject, ptr: *[*]u8, end: [*]u8) callconv(jsc.conv) jsc.JSValue { if (comptime Environment.enable_logs) log_zig_structured_clone_deserialize("${typeName}"); - return @call(.always_inline, jsc.toJSHostCall, .{ globalObject, @src(), ${typeName}.onStructuredCloneDeserialize, .{globalObject, ptr, end} }); + return @call(bun.callmod_inline, jsc.toJSHostCall, .{ globalObject, @src(), ${typeName}.onStructuredCloneDeserialize, .{globalObject, ptr, end} }); } `; } else { diff --git a/src/sys/PosixStat.zig b/src/sys/PosixStat.zig index c8975032af..cf2c00e84d 100644 --- a/src/sys/PosixStat.zig +++ b/src/sys/PosixStat.zig @@ -1,7 +1,7 @@ /// POSIX-like stat structure with birthtime support for node:fs /// This extends the standard POSIX stat with birthtime (creation time) pub const PosixStat = extern struct { - dev: u64, + dev: i64, ino: u64, mode: u32, nlink: u64, diff --git a/test/leaksan.supp b/test/leaksan.supp index 630e64774d..2dcb525c87 100644 --- a/test/leaksan.supp +++ b/test/leaksan.supp @@ -96,7 +96,6 @@ leak:sql.postgres.protocol.FieldMessage.FieldMessage.init leak:JSC::intlCollatorAvailableLocales leak:Bun__canonicalizeIP leak:dlopen -leak:Bun::evaluateCommonJSModuleOnce leak:fse_run_loop leak:Zig::NapiClass_ConstructorFunction leak:bun.js.webcore.fetch.FetchTasklet.toResponse @@ -194,3 +193,4 @@ leak:ast.parseStmt.ParseStmt leak:bun.js.ModuleLoader.RuntimeTranspilerStore.TranspilerJob.run leak:bun.js.BuildMessage.BuildMessage.getNotes leak:sql.postgres.PostgresSQLQuery.doRun +leak:bun.js.node.node_fs.Arguments.Realpath.fromJS diff --git a/test/no-validate-leaksan.txt b/test/no-validate-leaksan.txt index c2cbec6ab2..b752aaf97b 100644 --- a/test/no-validate-leaksan.txt +++ b/test/no-validate-leaksan.txt @@ -193,6 +193,7 @@ test/regression/issue/02499/02499.test.ts test/js/node/test/parallel/test-http-server-stale-close.js test/js/third_party/comlink/comlink.test.ts test/regression/issue/22635/22635.test.ts +test/js/node/test/parallel/test-child-process-silent.js # Bun::JSNodeHTTPServerSocket::clearSocketData