From 317998fdd65aa4bbbbccb73242ee80c1c7417ae3 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Sun, 14 Jan 2024 05:36:31 -0800 Subject: [PATCH] Make `toBunString` increment the reference count (#8146) * Make `toBunString` increment the reference count * Fix WASI --------- Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> --- src/bun.js/ConsoleObject.zig | 12 ++++++-- src/bun.js/api/bun.zig | 36 +++++++++++++++++++++--- src/bun.js/api/bun/h2_frame_parser.zig | 3 +- src/bun.js/api/bun/socket.zig | 3 +- src/bun.js/api/glob.zig | 2 +- src/bun.js/bindings/BunString.cpp | 9 +++--- src/bun.js/bindings/ZigGlobalObject.cpp | 8 ++++-- src/bun.js/bindings/bindings.zig | 23 ++++++++++++++- src/bun.js/node/node_fs.zig | 1 + src/bun.js/node/types.zig | 13 ++++++--- src/bun.js/node/util/validators.zig | 1 + src/bun.js/test/expect.zig | 3 +- src/bun.js/test/jest.zig | 6 ++-- src/bun.js/web_worker.zig | 4 +-- src/bun.js/webcore/blob.zig | 37 +++++++++++++------------ src/bun.js/webcore/request.zig | 6 ++-- src/bun.js/webcore/response.zig | 5 ++-- src/bundler.zig | 12 +++++++- src/comptime_string_map.zig | 2 ++ src/deps/c_ares.zig | 1 + src/js_ast.zig | 1 + src/napi/napi.zig | 4 +++ src/resolver/resolver.zig | 1 + src/string.zig | 6 ++-- 24 files changed, 146 insertions(+), 53 deletions(-) diff --git a/src/bun.js/ConsoleObject.zig b/src/bun.js/ConsoleObject.zig index 004c0f9543..351c5d0bd1 100644 --- a/src/bun.js/ConsoleObject.zig +++ b/src/bun.js/ConsoleObject.zig @@ -455,7 +455,12 @@ const TablePrinter = struct { var stack_fallback = std.heap.stackFallback(@sizeOf(Column) * 16, this.globalObject.allocator()); var columns = try std.ArrayList(Column).initCapacity(stack_fallback.get(), 16); - defer columns.deinit(); + defer { + for (columns.items) |*col| { + col.name.deref(); + } + columns.deinit(); + } // create the first column " " which is always present columns.appendAssumeCapacity(.{ @@ -1674,10 +1679,11 @@ pub const Formatter = struct { this.writeWithFormatting(Writer, writer_, @TypeOf(slice), slice, this.globalThis, enable_ansi_colors); }, .String => { - var str: bun.String = bun.String.tryFromJS(value, this.globalThis) orelse { + const str: bun.String = bun.String.tryFromJS(value, this.globalThis) orelse { writer.failed = true; return; }; + defer str.deref(); this.addForNewLine(str.length()); if (this.quote_strings and jsType != .RegExpObject) { @@ -1812,7 +1818,7 @@ pub const Formatter = struct { ); // Strings are printed directly, otherwise we recurse. It is possible to end up in an infinite loop. if (result.isString()) { - writer.print("{}", .{result.toBunString(this.globalThis)}); + writer.print("{}", .{result.fmtString(this.globalThis)}); } else { this.format(ConsoleObject.Formatter.Tag.get(result, this.globalThis), Writer, writer_, result, this.globalThis, enable_ansi_colors); } diff --git a/src/bun.js/api/bun.zig b/src/bun.js/api/bun.zig index 1bbd920793..a1e6a23818 100644 --- a/src/bun.js/api/bun.zig +++ b/src/bun.js/api/bun.zig @@ -773,7 +773,18 @@ fn doResolve( } } - return doResolveWithArgs(globalThis, specifier.toBunString(globalThis), from.toBunString(globalThis), exception, is_esm, false); + const specifier_str = specifier.toBunString(globalThis); + defer specifier_str.deref(); + const from_str = from.toBunString(globalThis); + defer from_str.deref(); + return doResolveWithArgs( + globalThis, + specifier_str, + from_str, + exception, + is_esm, + false, + ); } fn doResolveWithArgs( @@ -868,9 +879,16 @@ export fn Bun__resolve( ) JSC.JSValue { var exception_ = [1]JSC.JSValueRef{null}; const exception = &exception_; - const value = doResolveWithArgs(global, specifier.toBunString(global), source.toBunString(global), exception, is_esm, true) orelse { + const specifier_str = specifier.toBunString(global); + defer specifier_str.deref(); + + const source_str = source.toBunString(global); + defer source_str.deref(); + + const value = doResolveWithArgs(global, specifier_str, source_str, exception, is_esm, true) orelse { return JSC.JSPromise.rejectedPromiseValue(global, exception_[0].?.value()); }; + return JSC.JSPromise.resolvedPromiseValue(global, value); } @@ -882,7 +900,14 @@ export fn Bun__resolveSync( ) JSC.JSValue { var exception_ = [1]JSC.JSValueRef{null}; const exception = &exception_; - return doResolveWithArgs(global, specifier.toBunString(global), source.toBunString(global), exception, is_esm, true) orelse { + + const specifier_str = specifier.toBunString(global); + defer specifier_str.deref(); + + const source_str = source.toBunString(global); + defer source_str.deref(); + + return doResolveWithArgs(global, specifier_str, source_str, exception, is_esm, true) orelse { return JSC.JSValue.fromRef(exception[0]); }; } @@ -894,8 +919,11 @@ export fn Bun__resolveSyncWithSource( is_esm: bool, ) JSC.JSValue { var exception_ = [1]JSC.JSValueRef{null}; + const specifier_str = specifier.toBunString(global); + defer specifier_str.deref(); + const exception = &exception_; - return doResolveWithArgs(global, specifier.toBunString(global), source.*, exception, is_esm, true) orelse { + return doResolveWithArgs(global, specifier_str, source.*, exception, is_esm, true) orelse { return JSC.JSValue.fromRef(exception[0]); }; } diff --git a/src/bun.js/api/bun/h2_frame_parser.zig b/src/bun.js/api/bun/h2_frame_parser.zig index d30823bcc3..8e4e28f2aa 100644 --- a/src/bun.js/api/bun/h2_frame_parser.zig +++ b/src/bun.js/api/bun/h2_frame_parser.zig @@ -2117,7 +2117,8 @@ pub const H2FrameParser = struct { const payload = array_buffer.slice(); this.sendData(stream_id, payload, close and !stream.waitForTrailers); } else if (bun.String.tryFromJS(data_arg, globalObject)) |bun_str| { - var zig_str = bun_str.toUTF8(bun.default_allocator); + defer bun_str.deref(); + var zig_str = bun_str.toUTF8WithoutRef(bun.default_allocator); defer zig_str.deinit(); const payload = zig_str.slice(); this.sendData(stream_id, payload, close and !stream.waitForTrailers); diff --git a/src/bun.js/api/bun/socket.zig b/src/bun.js/api/bun/socket.zig index 321872e600..d24629cbf3 100644 --- a/src/bun.js/api/bun/socket.zig +++ b/src/bun.js/api/bun/socket.zig @@ -1857,7 +1857,8 @@ fn NewSocket(comptime ssl: bool) type { globalObject.throw("sendfile() not implemented yet", .{}); return .{ .fail = {} }; } else if (bun.String.tryFromJS(args.ptr[0], globalObject)) |bun_str| { - var zig_str = bun_str.toUTF8(bun.default_allocator); + defer bun_str.deref(); + var zig_str = bun_str.toUTF8WithoutRef(bun.default_allocator); defer zig_str.deinit(); var slice = zig_str.slice(); diff --git a/src/bun.js/api/glob.zig b/src/bun.js/api/glob.zig index 55ac123bf1..5e9f6e6fa0 100644 --- a/src/bun.js/api/glob.zig +++ b/src/bun.js/api/glob.zig @@ -376,7 +376,7 @@ pub fn constructor( return null; } - const pat_str: []u8 = pat_arg.toBunString(globalThis).toOwnedSlice(bun.default_allocator) catch @panic("OOM"); + const pat_str: []u8 = @constCast((pat_arg.toSliceClone(globalThis) orelse return null).slice()); const all_ascii = isAllAscii(pat_str); diff --git a/src/bun.js/bindings/BunString.cpp b/src/bun.js/bindings/BunString.cpp index a92d888af1..ba53c2c44f 100644 --- a/src/bun.js/bindings/BunString.cpp +++ b/src/bun.js/bindings/BunString.cpp @@ -102,16 +102,17 @@ BunString fromJS(JSC::JSGlobalObject* globalObject, JSValue value) { WTF::String str = value.toWTFString(globalObject); - if (str.isNull()) { - // failure to convert to string + if (UNLIKELY(str.isNull())) { return { BunStringTag::Dead }; } - if (str.length() == 0) { + if (UNLIKELY(str.length() == 0)) { return { BunStringTag::Empty }; } - return { BunStringTag::WTFStringImpl, { .wtf = str.impl() } }; + auto impl = str.releaseImpl(); + + return { BunStringTag::WTFStringImpl, { .wtf = impl.leakRef() } }; } extern "C" void BunString__toThreadSafe(BunString* str) diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp index 81042e7af7..8439848f47 100644 --- a/src/bun.js/bindings/ZigGlobalObject.cpp +++ b/src/bun.js/bindings/ZigGlobalObject.cpp @@ -4182,7 +4182,7 @@ static JSC::JSInternalPromise* rejectedInternalPromise(JSC::JSGlobalObject* glob JSC::JSInternalPromise* GlobalObject::moduleLoaderFetch(JSGlobalObject* globalObject, JSModuleLoader* loader, JSValue key, - JSValue value1, JSValue value2) + JSValue sourceValue, JSValue value2) { JSC::VM& vm = globalObject->vm(); @@ -4197,7 +4197,11 @@ JSC::JSInternalPromise* GlobalObject::moduleLoaderFetch(JSGlobalObject* globalOb } auto moduleKeyBun = Bun::toString(moduleKey); - auto source = Bun::toString(globalObject, value1); + auto sourceString = sourceValue.isString() + ? sourceValue.toWTFString(globalObject) + : String("undefined"_s); // WASM entry point expet "undefined" as the referrer. + + auto source = Bun::toString(sourceString); ErrorableResolvedSource res; res.success = false; res.result.err.code = 0; diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig index 664953d1e7..4146ce024f 100644 --- a/src/bun.js/bindings/bindings.zig +++ b/src/bun.js/bindings/bindings.zig @@ -4277,6 +4277,9 @@ pub const JSValue = enum(JSValueReprInt) { return cppFn("toZigString", .{ this, out, global }); } + /// Increments the reference count + /// + /// **You must call `.deref()` or it will leak memory** pub fn toBunString(this: JSValue, globalObject: *JSC.JSGlobalObject) bun.String { return bun.String.fromJS(this, globalObject); } @@ -4380,7 +4383,7 @@ pub const JSValue = enum(JSValueReprInt) { /// /// Remember that `Symbol` throws an exception when you call `toString()`. pub fn toSliceClone(this: JSValue, globalThis: *JSGlobalObject) ?ZigString.Slice { - return this.toSliceCloneWithAllocator(globalThis, globalThis.allocator()); + return this.toSliceCloneWithAllocator(globalThis, bun.default_allocator); } /// On exception or out of memory, this returns null, to make exception checks clearer. @@ -4734,6 +4737,24 @@ pub const JSValue = enum(JSValueReprInt) { }); } + pub const StringFormatter = struct { + value: JSC.JSValue, + globalObject: *JSC.JSGlobalObject, + + pub fn format(this: StringFormatter, comptime text: []const u8, opts: std.fmt.FormatOptions, writer: anytype) !void { + const str = this.value.toBunString(this.globalObject); + defer str.deref(); + try str.format(text, opts, writer); + } + }; + + pub fn fmtString(this: JSValue, globalObject: *JSC.JSGlobalObject) StringFormatter { + return .{ + .value = this, + .globalObject = globalObject, + }; + } + pub fn toFmt( this: JSValue, global: *JSGlobalObject, diff --git a/src/bun.js/node/node_fs.zig b/src/bun.js/node/node_fs.zig index 55e75cc09a..7cb5c79ab4 100644 --- a/src/bun.js/node/node_fs.zig +++ b/src/bun.js/node/node_fs.zig @@ -1655,6 +1655,7 @@ pub const Arguments = struct { if (next_val.isString()) { arguments.eat(); var str = next_val.toBunString(ctx.ptr()); + defer str.deref(); const utf8 = str.utf8(); if (strings.eqlComptime(utf8, "dir")) break :link_type .dir; if (strings.eqlComptime(utf8, "file")) break :link_type .file; diff --git a/src/bun.js/node/types.zig b/src/bun.js/node/types.zig index d0f92159cf..e9d827f00c 100644 --- a/src/bun.js/node/types.zig +++ b/src/bun.js/node/types.zig @@ -245,7 +245,8 @@ pub const StringOrBuffer = union(enum) { return try allocator.dupe(u8, array_buffer.byteSlice()); } - var str = bun.String.tryFromJS(value, globalObject) orelse return error.JSError; + const str = bun.String.tryFromJS(value, globalObject) orelse return error.JSError; + defer str.deref(); const result = try str.toOwnedSlice(allocator); defer globalObject.vm().reportExtraMemory(result.len); @@ -322,9 +323,12 @@ pub const StringOrBuffer = union(enum) { ) ?StringOrBuffer { return switch (value.jsType()) { JSC.JSValue.JSType.String, JSC.JSValue.JSType.StringObject, JSC.JSValue.JSType.DerivedStringObject, JSC.JSValue.JSType.Object => { - var str = bun.String.tryFromJS(value, global) orelse return null; + const str = bun.String.tryFromJS(value, global) orelse return null; + if (is_async) { - var sliced = str.toThreadSafeSlice(allocator); + defer str.deref(); + var possible_clone = str; + var sliced = possible_clone.toThreadSafeSlice(allocator); sliced.reportExtraMemory(global.vm()); if (sliced.underlying.isEmpty()) { @@ -333,7 +337,6 @@ pub const StringOrBuffer = union(enum) { return StringOrBuffer{ .threadsafe_string = sliced }; } else { - str.ref(); return StringOrBuffer{ .string = str.toSlice(allocator) }; } }, @@ -376,6 +379,7 @@ pub const StringOrBuffer = union(enum) { } var str = bun.String.tryFromJS(value, global) orelse return null; + defer str.deref(); if (str.isEmpty()) { return fromJSMaybeAsync(global, allocator, value, is_async); } @@ -698,6 +702,7 @@ pub const PathLike = union(enum) { JSC.JSValue.JSType.DerivedStringObject, => { var str = arg.toBunString(ctx); + defer str.deref(); arguments.eat(); diff --git a/src/bun.js/node/util/validators.zig b/src/bun.js/node/util/validators.zig index f46698a6bc..93de1f8f4d 100644 --- a/src/bun.js/node/util/validators.zig +++ b/src/bun.js/node/util/validators.zig @@ -232,6 +232,7 @@ pub fn validateUndefined(globalThis: *JSGlobalObject, value: JSValue, comptime n pub fn validateStringEnum(comptime T: type, globalThis: *JSGlobalObject, value: JSValue, comptime name_fmt: string, name_args: anytype) !T { const str = value.toBunString(globalThis); + defer str.deref(); inline for (@typeInfo(T).Enum.fields) |enum_field| { if (str.eqlComptime(enum_field.name)) return @field(T, enum_field.name); diff --git a/src/bun.js/test/expect.zig b/src/bun.js/test/expect.zig index de4a10d7e7..648d786bda 100644 --- a/src/bun.js/test/expect.zig +++ b/src/bun.js/test/expect.zig @@ -4357,7 +4357,8 @@ pub const Expect = struct { if (pass or silent) return pass; // handle failure - var message_text: bun.String = undefined; + var message_text: bun.String = bun.String.dead; + defer message_text.deref(); if (message.isUndefined()) { message_text = bun.String.static("No message was specified for this matcher."); } else if (message.isString()) { diff --git a/src/bun.js/test/jest.zig b/src/bun.js/test/jest.zig index 52a2871386..b195a0b9dc 100644 --- a/src/bun.js/test/jest.zig +++ b/src/bun.js/test/jest.zig @@ -1829,9 +1829,9 @@ fn consumeArg( ) !void { const allocator = getAllocator(globalThis); if (should_write) { - const owned_slice = try arg.*.toBunString(globalThis).toOwnedSlice(allocator); - defer allocator.free(owned_slice); - try array_list.*.appendSlice(allocator, owned_slice); + const owned_slice = arg.toSliceOrNull(globalThis) orelse return error.Failed; + defer owned_slice.deinit(); + try array_list.appendSlice(allocator, owned_slice.slice()); } else { try array_list.appendSlice(allocator, fallback); } diff --git a/src/bun.js/web_worker.zig b/src/bun.js/web_worker.zig index 0b10fcc3a1..13e1ede9ca 100644 --- a/src/bun.js/web_worker.zig +++ b/src/bun.js/web_worker.zig @@ -92,8 +92,7 @@ pub const WebWorker = struct { defer temp_log.deinit(); var resolved_entry_point = parent.bundler.resolveEntryPoint(spec_slice.slice()) catch { - var out = temp_log.toJS(parent.global, bun.default_allocator, "Error resolving Worker entry point").toBunString(parent.global); - out.ref(); + const out = temp_log.toJS(parent.global, bun.default_allocator, "Error resolving Worker entry point").toBunString(parent.global); error_message.* = out; return null; }; @@ -201,6 +200,7 @@ pub const WebWorker = struct { if (vm.log.msgs.items.len == 0) return; const err = vm.log.toJS(vm.global, bun.default_allocator, "Error in worker"); const str = err.toBunString(vm.global); + defer str.deref(); WebWorker__dispatchError(vm.global, this.cpp_worker, str, err); } diff --git a/src/bun.js/webcore/blob.zig b/src/bun.js/webcore/blob.zig index e9e5808f5d..58d024776c 100644 --- a/src/bun.js/webcore/blob.zig +++ b/src/bun.js/webcore/blob.zig @@ -918,6 +918,7 @@ pub const Blob = struct { if (len < 256 * 1024) { const str = data.toBunString(globalThis); + defer str.deref(); const pathlike: JSC.Node.PathOrFileDescriptor = if (path_or_blob == .path) path_or_blob.path @@ -1292,25 +1293,27 @@ pub const Blob = struct { globalThis.throwInvalidArguments("new File(bits, name) expects at least 2 arguments", .{}); return null; } - - const name_value_str = bun.String.tryFromJS(args[1], globalThis) orelse { - globalThis.throwInvalidArguments("new File(bits, name) expects string as the second argument", .{}); - return null; - }; - - blob = get(globalThis, args[0], false, true) catch |err| { - if (err == error.InvalidArguments) { - globalThis.throwInvalidArguments("new File(bits, name) expects iterable as the first argument", .{}); + { + const name_value_str = bun.String.tryFromJS(args[1], globalThis) orelse { + globalThis.throwInvalidArguments("new File(bits, name) expects string as the second argument", .{}); return null; - } - globalThis.throwOutOfMemory(); - return null; - }; + }; + defer name_value_str.deref(); - if (blob.store) |store_| { - store_.data.bytes.stored_name = bun.PathString.init( - (name_value_str.toUTF8WithoutRef(bun.default_allocator).clone(bun.default_allocator) catch unreachable).slice(), - ); + blob = get(globalThis, args[0], false, true) catch |err| { + if (err == error.InvalidArguments) { + globalThis.throwInvalidArguments("new File(bits, name) expects iterable as the first argument", .{}); + return null; + } + globalThis.throwOutOfMemory(); + return null; + }; + + if (blob.store) |store_| { + store_.data.bytes.stored_name = bun.PathString.init( + (name_value_str.toUTF8WithoutRef(bun.default_allocator).clone(bun.default_allocator) catch unreachable).slice(), + ); + } } if (args.len > 2) { diff --git a/src/bun.js/webcore/request.zig b/src/bun.js/webcore/request.zig index 509d61a316..3638191f6b 100644 --- a/src/bun.js/webcore/request.zig +++ b/src/bun.js/webcore/request.zig @@ -487,7 +487,7 @@ pub const Request = struct { _ = req.body.unref(); return null; }; - req.url = str.dupeRef(); + req.url = str; if (!req.url.isEmpty()) fields.insert(.url); @@ -588,7 +588,7 @@ pub const Request = struct { if (!fields.contains(.url)) { if (value.fastGet(globalThis, .url)) |url| { - req.url = bun.String.fromJS(url, globalThis).dupeRef(); + req.url = bun.String.fromJS(url, globalThis); if (!req.url.isEmpty()) fields.insert(.url); @@ -601,7 +601,7 @@ pub const Request = struct { _ = req.body.unref(); return null; }; - req.url = str.dupeRef(); + req.url = str; if (!req.url.isEmpty()) fields.insert(.url); } diff --git a/src/bun.js/webcore/response.zig b/src/bun.js/webcore/response.zig index f3613840a6..a47ee9eeb5 100644 --- a/src/bun.js/webcore/response.zig +++ b/src/bun.js/webcore/response.zig @@ -567,7 +567,7 @@ pub const Response = struct { } if (response_init.fastGet(ctx, .statusText)) |status_text| { - result.status_text = bun.String.fromJS(status_text, ctx).dupeRef(); + result.status_text = bun.String.fromJS(status_text, ctx); } if (response_init.fastGet(ctx, .method)) |method_value| { @@ -1944,6 +1944,7 @@ pub const Fetch = struct { } } } else if (bun.String.tryFromJS(first_arg, globalThis)) |str| { + defer str.deref(); if (str.isEmpty()) { const err = JSC.toTypeError(.ERR_INVALID_ARG_VALUE, fetch_error_blank_url, .{}, ctx); // clean hostname if any @@ -2220,7 +2221,7 @@ pub const Fetch = struct { prepare_body: { const opened_fd_res: JSC.Node.Maybe(bun.FileDescriptor) = switch (body.Blob.store.?.data.file.pathlike) { .fd => |fd| bun.sys.dup(fd), - .path => |path| bun.sys.open(path.sliceZ(&globalThis.bunVM().nodeFS().sync_error_buf), if(Environment.isWindows) std.os.O.RDONLY else std.os.O.RDONLY | std.os.O.NOCTTY, 0), + .path => |path| bun.sys.open(path.sliceZ(&globalThis.bunVM().nodeFS().sync_error_buf), if (Environment.isWindows) std.os.O.RDONLY else std.os.O.RDONLY | std.os.O.NOCTTY, 0), }; const opened_fd = switch (opened_fd_res) { diff --git a/src/bundler.zig b/src/bundler.zig index a4b8e9e73f..4ae07ace9a 100644 --- a/src/bundler.zig +++ b/src/bundler.zig @@ -145,7 +145,8 @@ pub const PluginRunner = struct { return null; } - var file_path = path_value.toBunString(global); + const file_path = path_value.toBunString(global); + defer file_path.deref(); if (file_path.length() == 0) { log.addError( @@ -178,18 +179,22 @@ pub const PluginRunner = struct { const namespace_str = namespace_value.toBunString(global); if (namespace_str.length() == 0) { + namespace_str.deref(); break :brk bun.String.init("file"); } if (namespace_str.eqlComptime("file")) { + namespace_str.deref(); break :brk bun.String.init("file"); } if (namespace_str.eqlComptime("bun")) { + namespace_str.deref(); break :brk bun.String.init("bun"); } if (namespace_str.eqlComptime("node")) { + namespace_str.deref(); break :brk bun.String.init("node"); } @@ -200,6 +205,7 @@ pub const PluginRunner = struct { break :brk bun.String.init("file"); }; + defer user_namespace.deref(); if (static_namespace) { return Fs.Path.initWithNamespace( @@ -275,14 +281,17 @@ pub const PluginRunner = struct { } if (namespace_str.eqlComptime("file")) { + defer namespace_str.deref(); break :brk bun.String.static("file"); } if (namespace_str.eqlComptime("bun")) { + defer namespace_str.deref(); break :brk bun.String.static("bun"); } if (namespace_str.eqlComptime("node")) { + defer namespace_str.deref(); break :brk bun.String.static("node"); } @@ -293,6 +302,7 @@ pub const PluginRunner = struct { break :brk bun.String.static("file"); }; + defer user_namespace.deref(); // Our super slow way of cloning the string into memory owned by JSC const combined_string = std.fmt.allocPrint( diff --git a/src/comptime_string_map.zig b/src/comptime_string_map.zig index 7b40b4aecd..f747a72152 100644 --- a/src/comptime_string_map.zig +++ b/src/comptime_string_map.zig @@ -172,6 +172,7 @@ pub fn ComptimeStringMapWithKeyType(comptime KeyType: type, comptime V: type, co } const str = @import("root").bun.String.tryFromJS(input, globalThis) orelse return null; + defer str.deref(); return getWithEql(str, @import("root").bun.String.eqlComptime); } @@ -184,6 +185,7 @@ pub fn ComptimeStringMapWithKeyType(comptime KeyType: type, comptime V: type, co } const str = @import("root").bun.String.tryFromJS(input, globalThis) orelse return null; + defer str.deref(); return str.inMapCaseInsensitive(@This()); } diff --git a/src/deps/c_ares.zig b/src/deps/c_ares.zig index a35c3b03c3..ad4a004233 100644 --- a/src/deps/c_ares.zig +++ b/src/deps/c_ares.zig @@ -1521,6 +1521,7 @@ pub export fn Bun__canonicalizeIP( const addr_arg = args.nextEat().?; if (bun.String.tryFromJS(addr_arg, globalThis)) |addr| { + defer addr.deref(); const addr_slice = addr.toSlice(bun.default_allocator); const addr_str = addr_slice.slice(); if (addr_str.len >= INET6_ADDRSTRLEN) { diff --git a/src/js_ast.zig b/src/js_ast.zig index 2454ce0d70..1ac0220003 100644 --- a/src/js_ast.zig +++ b/src/js_ast.zig @@ -7220,6 +7220,7 @@ pub const Macro = struct { }, .String => { var bun_str = value.toBunString(this.global); + defer bun_str.deref(); // encode into utf16 so the printer escapes the string correctly var utf16_bytes = this.allocator.alloc(u16, bun_str.length()) catch unreachable; diff --git a/src/napi/napi.zig b/src/napi/napi.zig index f371336aec..796a3b0636 100644 --- a/src/napi/napi.zig +++ b/src/napi/napi.zig @@ -408,6 +408,8 @@ pub export fn napi_get_value_string_latin1(env: napi_env, value: napi_value, buf const buf_ptr = @as(?[*:0]u8, @ptrCast(buf_ptr_)); const str = value.toBunString(env); + defer str.deref(); + var buf = buf_ptr orelse { if (result_ptr) |result| { result.* = str.latin1ByteLength(); @@ -461,6 +463,8 @@ pub export fn napi_get_value_string_utf16(env: napi_env, value: napi_value, buf_ log("napi_get_value_string_utf16", .{}); defer value.ensureStillAlive(); const str = value.toBunString(env); + defer str.deref(); + var buf = buf_ptr orelse { if (result_ptr) |result| { result.* = str.utf16ByteLength(); diff --git a/src/resolver/resolver.zig b/src/resolver/resolver.zig index ff436be938..b364914a97 100644 --- a/src/resolver/resolver.zig +++ b/src/resolver/resolver.zig @@ -3243,6 +3243,7 @@ pub const Resolver = struct { } const in_str = argument.toBunString(globalThis); + defer in_str.deref(); const r = &globalThis.bunVM().bundler.resolver; return nodeModulePathsJSValue(r, in_str, globalThis); } diff --git a/src/string.zig b/src/string.zig index 93afb1658c..969301c8ab 100644 --- a/src/string.zig +++ b/src/string.zig @@ -496,6 +496,7 @@ pub const String = extern struct { } pub fn toErrorInstance(this: *const String, globalObject: *JSC.JSGlobalObject) JSC.JSValue { + defer this.deref(); return JSC__createError(globalObject, this); } @@ -1138,15 +1139,14 @@ pub const String = extern struct { } pub export fn BunString__getStringWidth(globalObject: *JSC.JSGlobalObject, callFrame: *JSC.CallFrame) callconv(.C) JSC.JSValue { - var str: String = String.dead; - const args = callFrame.arguments(1).slice(); if (args.len == 0 or !args.ptr[0].isString()) { return JSC.jsNumber(@as(i32, 0)); } - str = args[0].toBunString(globalObject); + const str = args[0].toBunString(globalObject); + defer str.deref(); if (str.isEmpty()) { return JSC.jsNumber(@as(i32, 0));