From 1cfc3647853123efc0fda991180e337d8a72eac5 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 4 Jul 2024 07:19:08 +0200 Subject: [PATCH 1/6] tsan: build dynamic library on Apple platforms --- src/Compilation.zig | 3 +++ src/libtsan.zig | 37 +++++++++++++++++++++++++++++++------ 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/src/Compilation.zig b/src/Compilation.zig index 343b22d2b1..412798e09a 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -188,6 +188,9 @@ libunwind_static_lib: ?CRTFile = null, /// Populated when we build the TSAN static library. A Job to build this is placed in the queue /// and resolved before calling linker.flush(). tsan_static_lib: ?CRTFile = null, +/// Populated when we build the TSAN dynamic library. A Job to build this is placed in the queue +/// and resolved before calling linker.flush(). +tsan_dynamic_lib: ?CRTFile = null, /// Populated when we build the libc static library. A Job to build this is placed in the queue /// and resolved before calling linker.flush(). libc_static_lib: ?CRTFile = null, diff --git a/src/libtsan.zig b/src/libtsan.zig index 1aa32e6ff0..4164200b47 100644 --- a/src/libtsan.zig +++ b/src/libtsan.zig @@ -25,10 +25,20 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); - const root_name = "tsan"; - const output_mode = .Lib; - const link_mode = .static; const target = comp.getTarget(); + const root_name = switch (target.os.tag) { + // On Apple platforms, we use the same name as LLVM and Apple so that we correctly + // mark the images as instrumented when traversing them when TSAN dylib is + // initialized. + .macos => "clang_rt.tsan_osx_dynamic", + .ios => switch (target.abi) { + .simulator => "clang_rt.tsan_iossim_dynamic", + else => "clang_rt.tsan_ios_dynamic", + }, + else => "tsan", + }; + const link_mode: std.builtin.LinkMode = if (target.isDarwin()) .dynamic else .static; + const output_mode = .Lib; const basename = try std.zig.binNameAlloc(arena, .{ .root_name = root_name, .target = target, @@ -43,6 +53,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo const optimize_mode = comp.compilerRtOptMode(); const strip = comp.compilerRtStrip(); + const link_libcpp = target.isDarwin(); const config = Compilation.Config.resolve(.{ .output_mode = output_mode, @@ -54,6 +65,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo .root_optimize_mode = optimize_mode, .root_strip = strip, .link_libc = true, + .link_libcpp = link_libcpp, }) catch |err| { comp.setMiscFailure( .libtsan, @@ -272,6 +284,12 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo }); } + const skip_linker_dependencies = !target.isDarwin(); + const linker_allow_shlib_undefined = target.isDarwin(); + const install_name = if (target.isDarwin()) + try std.fmt.allocPrintZ(arena, "@rpath/{s}", .{basename}) + else + null; const sub_compilation = Compilation.create(comp.gpa, arena, .{ .local_cache_directory = comp.global_cache_directory, .global_cache_directory = comp.global_cache_directory, @@ -294,7 +312,9 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo .verbose_cimport = comp.verbose_cimport, .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .clang_passthrough_mode = comp.clang_passthrough_mode, - .skip_linker_dependencies = true, + .skip_linker_dependencies = skip_linker_dependencies, + .linker_allow_shlib_undefined = linker_allow_shlib_undefined, + .install_name = install_name, }) catch |err| { comp.setMiscFailure( .libtsan, @@ -317,8 +337,13 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo }, }; - assert(comp.tsan_static_lib == null); - comp.tsan_static_lib = try sub_compilation.toCrtFile(); + assert(comp.tsan_static_lib == null and comp.tsan_dynamic_lib == null); + + if (target.isDarwin()) { + comp.tsan_dynamic_lib = try sub_compilation.toCrtFile(); + } else { + comp.tsan_static_lib = try sub_compilation.toCrtFile(); + } } const tsan_sources = [_][]const u8{ From c9d19ebb7a3d6996ec8b299d1698adf6737d73e5 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 4 Jul 2024 07:21:01 +0200 Subject: [PATCH 2/6] macho: link dynamic TSAN lib --- src/link/MachO.zig | 21 +++++++++++++++------ src/link/MachO/load_commands.zig | 2 +- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/link/MachO.zig b/src/link/MachO.zig index dd185fcaec..52b57a2c58 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -150,6 +150,7 @@ no_implicit_dylibs: bool = false, /// Whether the linker should parse and always force load objects containing ObjC in archives. // TODO: in Zig we currently take -ObjC as always on force_load_objc: bool = true, +rpaths: std.ArrayListUnmanaged([]const u8) = .{}, /// Hot-code swapping state. hot_state: if (is_hot_update_compatible) HotUpdateState else struct {} = .{}, @@ -192,7 +193,7 @@ pub fn createEmpty( null else try std.fmt.allocPrint(arena, "{s}.o", .{emit.sub_path}); - const allow_shlib_undefined = options.allow_shlib_undefined orelse comp.config.any_sanitize_thread; + const allow_shlib_undefined = options.allow_shlib_undefined orelse false; const self = try arena.create(MachO); self.* = .{ @@ -358,6 +359,8 @@ pub fn deinit(self: *MachO) void { } self.thunks.deinit(gpa); self.unwind_records.deinit(gpa); + + self.rpaths.deinit(gpa); } pub fn flush(self: *MachO, arena: Allocator, prog_node: std.Progress.Node) link.File.FlushError!void { @@ -395,6 +398,9 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: std.Progress.Node) if (self.base.isStaticLib()) return relocatable.flushStaticLib(self, comp, module_obj_path); if (self.base.isObject()) return relocatable.flushObject(self, comp, module_obj_path); + try self.rpaths.ensureUnusedCapacity(gpa, self.base.rpath_list.len); + self.rpaths.appendSliceAssumeCapacity(self.base.rpath_list); + var positionals = std.ArrayList(Compilation.LinkObject).init(gpa); defer positionals.deinit(); @@ -413,7 +419,10 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: std.Progress.Node) // TSAN if (comp.config.any_sanitize_thread) { - try positionals.append(.{ .path = comp.tsan_static_lib.?.full_object_path }); + const path = comp.tsan_dynamic_lib.?.full_object_path; + try positionals.append(.{ .path = path }); + const basename = std.fs.path.dirname(path) orelse "."; + try self.rpaths.append(gpa, basename); } for (positionals.items) |obj| { @@ -771,7 +780,7 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void { try argv.append(syslibroot); } - for (self.base.rpath_list) |rpath| { + for (self.rpaths.items) |rpath| { try argv.append("-rpath"); try argv.append(rpath); } @@ -831,7 +840,7 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void { } if (comp.config.any_sanitize_thread) { - try argv.append(comp.tsan_static_lib.?.full_object_path); + try argv.append(comp.tsan_dynamic_lib.?.full_object_path); } for (self.lib_dirs) |lib_dir| { @@ -3015,8 +3024,8 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } { ncmds += 1; } - try load_commands.writeRpathLCs(self.base.rpath_list, writer); - ncmds += self.base.rpath_list.len; + try load_commands.writeRpathLCs(self.rpaths.items, writer); + ncmds += self.rpaths.items.len; try writer.writeStruct(macho.source_version_command{ .version = 0 }); ncmds += 1; diff --git a/src/link/MachO/load_commands.zig b/src/link/MachO/load_commands.zig index 394253db48..8719d92ea8 100644 --- a/src/link/MachO/load_commands.zig +++ b/src/link/MachO/load_commands.zig @@ -61,7 +61,7 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32 } // LC_RPATH { - for (macho_file.base.rpath_list) |rpath| { + for (macho_file.rpaths.items) |rpath| { sizeofcmds += calcInstallNameLen( @sizeOf(macho.rpath_command), rpath, From 76c3b6b794ebc9ddb910e369bbf2d121a01e06d8 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 4 Jul 2024 07:26:28 +0200 Subject: [PATCH 3/6] tsan: add workaround for TSAN Apple bug Addresses TSAN bug on Apple platforms by always setting the headerpad size to a non-zero value when building the TSAN dylib. --- src/libtsan.zig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libtsan.zig b/src/libtsan.zig index 4164200b47..b7d3a9dda2 100644 --- a/src/libtsan.zig +++ b/src/libtsan.zig @@ -290,6 +290,8 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo try std.fmt.allocPrintZ(arena, "@rpath/{s}", .{basename}) else null; + // This is temp conditional on resolving https://github.com/llvm/llvm-project/issues/97627 upstream. + const headerpad_size: ?u32 = if (target.isDarwin()) 32 else null; const sub_compilation = Compilation.create(comp.gpa, arena, .{ .local_cache_directory = comp.global_cache_directory, .global_cache_directory = comp.global_cache_directory, @@ -315,6 +317,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo .skip_linker_dependencies = skip_linker_dependencies, .linker_allow_shlib_undefined = linker_allow_shlib_undefined, .install_name = install_name, + .headerpad_size = headerpad_size, }) catch |err| { comp.setMiscFailure( .libtsan, From 6756aaccf14e168132cabe8e0d7933f4fd51e9a9 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 4 Jul 2024 22:01:19 +0200 Subject: [PATCH 4/6] macho: do not save rpaths globally in the driver --- src/link/MachO.zig | 32 ++++++++++---------- src/link/MachO/load_commands.zig | 50 +++++++++++++++++++------------- 2 files changed, 47 insertions(+), 35 deletions(-) diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 52b57a2c58..76bea81766 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -150,7 +150,6 @@ no_implicit_dylibs: bool = false, /// Whether the linker should parse and always force load objects containing ObjC in archives. // TODO: in Zig we currently take -ObjC as always on force_load_objc: bool = true, -rpaths: std.ArrayListUnmanaged([]const u8) = .{}, /// Hot-code swapping state. hot_state: if (is_hot_update_compatible) HotUpdateState else struct {} = .{}, @@ -359,8 +358,6 @@ pub fn deinit(self: *MachO) void { } self.thunks.deinit(gpa); self.unwind_records.deinit(gpa); - - self.rpaths.deinit(gpa); } pub fn flush(self: *MachO, arena: Allocator, prog_node: std.Progress.Node) link.File.FlushError!void { @@ -398,9 +395,6 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: std.Progress.Node) if (self.base.isStaticLib()) return relocatable.flushStaticLib(self, comp, module_obj_path); if (self.base.isObject()) return relocatable.flushObject(self, comp, module_obj_path); - try self.rpaths.ensureUnusedCapacity(gpa, self.base.rpath_list.len); - self.rpaths.appendSliceAssumeCapacity(self.base.rpath_list); - var positionals = std.ArrayList(Compilation.LinkObject).init(gpa); defer positionals.deinit(); @@ -419,10 +413,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: std.Progress.Node) // TSAN if (comp.config.any_sanitize_thread) { - const path = comp.tsan_dynamic_lib.?.full_object_path; - try positionals.append(.{ .path = path }); - const basename = std.fs.path.dirname(path) orelse "."; - try self.rpaths.append(gpa, basename); + try positionals.append(.{ .path = comp.tsan_dynamic_lib.?.full_object_path }); } for (positionals.items) |obj| { @@ -780,7 +771,7 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void { try argv.append(syslibroot); } - for (self.rpaths.items) |rpath| { + for (self.base.rpath_list) |rpath| { try argv.append("-rpath"); try argv.append(rpath); } @@ -840,7 +831,9 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void { } if (comp.config.any_sanitize_thread) { - try argv.append(comp.tsan_dynamic_lib.?.full_object_path); + const path = comp.tsan_dynamic_lib.?.full_object_path; + try argv.append(path); + try argv.appendSlice(&.{ "-rpath", std.fs.path.dirname(path) orelse "." }); } for (self.lib_dirs) |lib_dir| { @@ -2968,7 +2961,8 @@ pub fn writeStrtab(self: *MachO, off: u32) !u32 { } fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } { - const gpa = self.base.comp.gpa; + const comp = self.base.comp; + const gpa = comp.gpa; const needed_size = try load_commands.calcLoadCommandsSize(self, false); const buffer = try gpa.alloc(u8, needed_size); defer gpa.free(buffer); @@ -3024,8 +3018,16 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } { ncmds += 1; } - try load_commands.writeRpathLCs(self.rpaths.items, writer); - ncmds += self.rpaths.items.len; + for (self.base.rpath_list) |rpath| { + try load_commands.writeRpathLC(rpath, writer); + ncmds += 1; + } + if (comp.config.any_sanitize_thread) { + const path = comp.tsan_dynamic_lib.?.full_object_path; + const rpath = std.fs.path.dirname(path) orelse "."; + try load_commands.writeRpathLC(rpath, writer); + ncmds += 1; + } try writer.writeStruct(macho.source_version_command{ .version = 0 }); ncmds += 1; diff --git a/src/link/MachO/load_commands.zig b/src/link/MachO/load_commands.zig index 8719d92ea8..003612fa2f 100644 --- a/src/link/MachO/load_commands.zig +++ b/src/link/MachO/load_commands.zig @@ -18,6 +18,9 @@ fn calcInstallNameLen(cmd_size: u64, name: []const u8, assume_max_path_len: bool } pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32 { + const comp = macho_file.base.comp; + const gpa = comp.gpa; + var sizeofcmds: u64 = 0; // LC_SEGMENT_64 @@ -48,7 +51,6 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32 } // LC_ID_DYLIB if (macho_file.base.isDynLib()) { - const gpa = macho_file.base.comp.gpa; const emit = macho_file.base.emit; const install_name = macho_file.install_name orelse try emit.directory.join(gpa, &.{emit.sub_path}); @@ -61,7 +63,17 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32 } // LC_RPATH { - for (macho_file.rpaths.items) |rpath| { + for (macho_file.base.rpath_list) |rpath| { + sizeofcmds += calcInstallNameLen( + @sizeOf(macho.rpath_command), + rpath, + assume_max_path_len, + ); + } + + if (comp.config.any_sanitize_thread) { + const path = comp.tsan_dynamic_lib.?.full_object_path; + const rpath = std.fs.path.dirname(path) orelse "."; sizeofcmds += calcInstallNameLen( @sizeOf(macho.rpath_command), rpath, @@ -245,24 +257,22 @@ pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void { }, writer); } -pub fn writeRpathLCs(rpaths: []const []const u8, writer: anytype) !void { - for (rpaths) |rpath| { - const rpath_len = rpath.len + 1; - const cmdsize = @as(u32, @intCast(mem.alignForward( - u64, - @sizeOf(macho.rpath_command) + rpath_len, - @sizeOf(u64), - ))); - try writer.writeStruct(macho.rpath_command{ - .cmdsize = cmdsize, - .path = @sizeOf(macho.rpath_command), - }); - try writer.writeAll(rpath); - try writer.writeByte(0); - const padding = cmdsize - @sizeOf(macho.rpath_command) - rpath_len; - if (padding > 0) { - try writer.writeByteNTimes(0, padding); - } +pub fn writeRpathLC(rpath: []const u8, writer: anytype) !void { + const rpath_len = rpath.len + 1; + const cmdsize = @as(u32, @intCast(mem.alignForward( + u64, + @sizeOf(macho.rpath_command) + rpath_len, + @sizeOf(u64), + ))); + try writer.writeStruct(macho.rpath_command{ + .cmdsize = cmdsize, + .path = @sizeOf(macho.rpath_command), + }); + try writer.writeAll(rpath); + try writer.writeByte(0); + const padding = cmdsize - @sizeOf(macho.rpath_command) - rpath_len; + if (padding > 0) { + try writer.writeByteNTimes(0, padding); } } From e42e12dbbf8ebae65589ff08c3b5a454d2d67441 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 4 Jul 2024 22:03:31 +0200 Subject: [PATCH 5/6] tsan: fix wording in comments --- src/libtsan.zig | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/libtsan.zig b/src/libtsan.zig index b7d3a9dda2..bc72f9d86c 100644 --- a/src/libtsan.zig +++ b/src/libtsan.zig @@ -27,9 +27,8 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo const target = comp.getTarget(); const root_name = switch (target.os.tag) { - // On Apple platforms, we use the same name as LLVM and Apple so that we correctly - // mark the images as instrumented when traversing them when TSAN dylib is - // initialized. + // On Apple platforms, we use the same name as LLVM because the + // TSAN library implementation hard-codes a check for these names. .macos => "clang_rt.tsan_osx_dynamic", .ios => switch (target.abi) { .simulator => "clang_rt.tsan_iossim_dynamic", @@ -290,7 +289,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo try std.fmt.allocPrintZ(arena, "@rpath/{s}", .{basename}) else null; - // This is temp conditional on resolving https://github.com/llvm/llvm-project/issues/97627 upstream. + // Workaround for https://github.com/llvm/llvm-project/issues/97627 const headerpad_size: ?u32 = if (target.isDarwin()) 32 else null; const sub_compilation = Compilation.create(comp.gpa, arena, .{ .local_cache_directory = comp.global_cache_directory, From d2cace58bd031e72b830ebd42f5946f4000e52a4 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 4 Jul 2024 22:09:57 +0200 Subject: [PATCH 6/6] Compilation: rename tsan_static_lib to tsan_lib --- src/Compilation.zig | 7 ++----- src/libtsan.zig | 9 ++------- src/link/Elf.zig | 6 +++--- src/link/MachO.zig | 6 +++--- src/link/MachO/load_commands.zig | 2 +- 5 files changed, 11 insertions(+), 19 deletions(-) diff --git a/src/Compilation.zig b/src/Compilation.zig index 412798e09a..b72a58f7fc 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -185,12 +185,9 @@ libcxxabi_static_lib: ?CRTFile = null, /// Populated when we build the libunwind static library. A Job to build this is placed in the queue /// and resolved before calling linker.flush(). libunwind_static_lib: ?CRTFile = null, -/// Populated when we build the TSAN static library. A Job to build this is placed in the queue +/// Populated when we build the TSAN library. A Job to build this is placed in the queue /// and resolved before calling linker.flush(). -tsan_static_lib: ?CRTFile = null, -/// Populated when we build the TSAN dynamic library. A Job to build this is placed in the queue -/// and resolved before calling linker.flush(). -tsan_dynamic_lib: ?CRTFile = null, +tsan_lib: ?CRTFile = null, /// Populated when we build the libc static library. A Job to build this is placed in the queue /// and resolved before calling linker.flush(). libc_static_lib: ?CRTFile = null, diff --git a/src/libtsan.zig b/src/libtsan.zig index bc72f9d86c..42b605bf3c 100644 --- a/src/libtsan.zig +++ b/src/libtsan.zig @@ -339,13 +339,8 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo }, }; - assert(comp.tsan_static_lib == null and comp.tsan_dynamic_lib == null); - - if (target.isDarwin()) { - comp.tsan_dynamic_lib = try sub_compilation.toCrtFile(); - } else { - comp.tsan_static_lib = try sub_compilation.toCrtFile(); - } + assert(comp.tsan_lib == null); + comp.tsan_lib = try sub_compilation.toCrtFile(); } const tsan_sources = [_][]const u8{ diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 5a14a544e8..b1048dfe9d 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1145,7 +1145,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: std.Progress.Node) l // TSAN if (comp.config.any_sanitize_thread) { - try positionals.append(.{ .path = comp.tsan_static_lib.?.full_object_path }); + try positionals.append(.{ .path = comp.tsan_lib.?.full_object_path }); } // libc @@ -1603,7 +1603,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { } if (comp.config.any_sanitize_thread) { - try argv.append(comp.tsan_static_lib.?.full_object_path); + try argv.append(comp.tsan_lib.?.full_object_path); } // libc @@ -2610,7 +2610,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, prog_node: std.Progress.Node) !void } if (comp.config.any_sanitize_thread) { - try argv.append(comp.tsan_static_lib.?.full_object_path); + try argv.append(comp.tsan_lib.?.full_object_path); } // libc diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 76bea81766..4dcc11ef53 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -413,7 +413,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: std.Progress.Node) // TSAN if (comp.config.any_sanitize_thread) { - try positionals.append(.{ .path = comp.tsan_dynamic_lib.?.full_object_path }); + try positionals.append(.{ .path = comp.tsan_lib.?.full_object_path }); } for (positionals.items) |obj| { @@ -831,7 +831,7 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void { } if (comp.config.any_sanitize_thread) { - const path = comp.tsan_dynamic_lib.?.full_object_path; + const path = comp.tsan_lib.?.full_object_path; try argv.append(path); try argv.appendSlice(&.{ "-rpath", std.fs.path.dirname(path) orelse "." }); } @@ -3023,7 +3023,7 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } { ncmds += 1; } if (comp.config.any_sanitize_thread) { - const path = comp.tsan_dynamic_lib.?.full_object_path; + const path = comp.tsan_lib.?.full_object_path; const rpath = std.fs.path.dirname(path) orelse "."; try load_commands.writeRpathLC(rpath, writer); ncmds += 1; diff --git a/src/link/MachO/load_commands.zig b/src/link/MachO/load_commands.zig index 003612fa2f..74d0c58cbd 100644 --- a/src/link/MachO/load_commands.zig +++ b/src/link/MachO/load_commands.zig @@ -72,7 +72,7 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32 } if (comp.config.any_sanitize_thread) { - const path = comp.tsan_dynamic_lib.?.full_object_path; + const path = comp.tsan_lib.?.full_object_path; const rpath = std.fs.path.dirname(path) orelse "."; sizeofcmds += calcInstallNameLen( @sizeOf(macho.rpath_command),