authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-07-05 00:33:46+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-07-05 00:33:46+02:00
logde61540c2d049b0774dd9c5e14aa8f65ed1c25ed
tree9185a2671aeeff937a0809a55a50bff7b9b83e8b
parentd9f1a952b8b0e19aafcf568b35cc220adbb4a7b5
parentd2cace58bd031e72b830ebd42f5946f4000e52a4
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #20496 from ziglang/macos-tsan


5 files changed, 79 insertions(+), 36 deletions(-)

src/Compilation.zig+2-2
...@@ -185,9 +185,9 @@ libcxxabi_static_lib: ?CRTFile = null,...@@ -185,9 +185,9 @@ libcxxabi_static_lib: ?CRTFile = null,
185/// Populated when we build the libunwind static library. A Job to build this is placed in the queue185/// Populated when we build the libunwind static library. A Job to build this is placed in the queue
186/// and resolved before calling linker.flush().186/// and resolved before calling linker.flush().
187libunwind_static_lib: ?CRTFile = null,187libunwind_static_lib: ?CRTFile = null,
188/// Populated when we build the TSAN static library. A Job to build this is placed in the queue188/// Populated when we build the TSAN library. A Job to build this is placed in the queue
189/// and resolved before calling linker.flush().189/// and resolved before calling linker.flush().
190tsan_static_lib: ?CRTFile = null,190tsan_lib: ?CRTFile = null,
191/// Populated when we build the libc static library. A Job to build this is placed in the queue191/// Populated when we build the libc static library. A Job to build this is placed in the queue
192/// and resolved before calling linker.flush().192/// and resolved before calling linker.flush().
193libc_static_lib: ?CRTFile = null,193libc_static_lib: ?CRTFile = null,
src/libtsan.zig+28-6
...@@ -25,10 +25,19 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo...@@ -25,10 +25,19 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
25 defer arena_allocator.deinit();25 defer arena_allocator.deinit();
26 const arena = arena_allocator.allocator();26 const arena = arena_allocator.allocator();
2727
28 const root_name = "tsan";
29 const output_mode = .Lib;
30 const link_mode = .static;
31 const target = comp.getTarget();28 const target = comp.getTarget();
29 const root_name = switch (target.os.tag) {
30 // On Apple platforms, we use the same name as LLVM because the
31 // TSAN library implementation hard-codes a check for these names.
32 .macos => "clang_rt.tsan_osx_dynamic",
33 .ios => switch (target.abi) {
34 .simulator => "clang_rt.tsan_iossim_dynamic",
35 else => "clang_rt.tsan_ios_dynamic",
36 },
37 else => "tsan",
38 };
39 const link_mode: std.builtin.LinkMode = if (target.isDarwin()) .dynamic else .static;
40 const output_mode = .Lib;
32 const basename = try std.zig.binNameAlloc(arena, .{41 const basename = try std.zig.binNameAlloc(arena, .{
33 .root_name = root_name,42 .root_name = root_name,
34 .target = target,43 .target = target,
...@@ -43,6 +52,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo...@@ -43,6 +52,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
4352
44 const optimize_mode = comp.compilerRtOptMode();53 const optimize_mode = comp.compilerRtOptMode();
45 const strip = comp.compilerRtStrip();54 const strip = comp.compilerRtStrip();
55 const link_libcpp = target.isDarwin();
4656
47 const config = Compilation.Config.resolve(.{57 const config = Compilation.Config.resolve(.{
48 .output_mode = output_mode,58 .output_mode = output_mode,
...@@ -54,6 +64,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo...@@ -54,6 +64,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
54 .root_optimize_mode = optimize_mode,64 .root_optimize_mode = optimize_mode,
55 .root_strip = strip,65 .root_strip = strip,
56 .link_libc = true,66 .link_libc = true,
67 .link_libcpp = link_libcpp,
57 }) catch |err| {68 }) catch |err| {
58 comp.setMiscFailure(69 comp.setMiscFailure(
59 .libtsan,70 .libtsan,
...@@ -272,6 +283,14 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo...@@ -272,6 +283,14 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
272 });283 });
273 }284 }
274285
286 const skip_linker_dependencies = !target.isDarwin();
287 const linker_allow_shlib_undefined = target.isDarwin();
288 const install_name = if (target.isDarwin())
289 try std.fmt.allocPrintZ(arena, "@rpath/{s}", .{basename})
290 else
291 null;
292 // Workaround for https://github.com/llvm/llvm-project/issues/97627
293 const headerpad_size: ?u32 = if (target.isDarwin()) 32 else null;
275 const sub_compilation = Compilation.create(comp.gpa, arena, .{294 const sub_compilation = Compilation.create(comp.gpa, arena, .{
276 .local_cache_directory = comp.global_cache_directory,295 .local_cache_directory = comp.global_cache_directory,
277 .global_cache_directory = comp.global_cache_directory,296 .global_cache_directory = comp.global_cache_directory,
...@@ -294,7 +313,10 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo...@@ -294,7 +313,10 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
294 .verbose_cimport = comp.verbose_cimport,313 .verbose_cimport = comp.verbose_cimport,
295 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,314 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
296 .clang_passthrough_mode = comp.clang_passthrough_mode,315 .clang_passthrough_mode = comp.clang_passthrough_mode,
297 .skip_linker_dependencies = true,316 .skip_linker_dependencies = skip_linker_dependencies,
317 .linker_allow_shlib_undefined = linker_allow_shlib_undefined,
318 .install_name = install_name,
319 .headerpad_size = headerpad_size,
298 }) catch |err| {320 }) catch |err| {
299 comp.setMiscFailure(321 comp.setMiscFailure(
300 .libtsan,322 .libtsan,
...@@ -317,8 +339,8 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo...@@ -317,8 +339,8 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
317 },339 },
318 };340 };
319341
320 assert(comp.tsan_static_lib == null);342 assert(comp.tsan_lib == null);
321 comp.tsan_static_lib = try sub_compilation.toCrtFile();343 comp.tsan_lib = try sub_compilation.toCrtFile();
322}344}
323345
324const tsan_sources = [_][]const u8{346const tsan_sources = [_][]const u8{
src/link/Elf.zig+3-3
...@@ -1145,7 +1145,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: std.Progress.Node) l...@@ -1145,7 +1145,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: std.Progress.Node) l
11451145
1146 // TSAN1146 // TSAN
1147 if (comp.config.any_sanitize_thread) {1147 if (comp.config.any_sanitize_thread) {
1148 try positionals.append(.{ .path = comp.tsan_static_lib.?.full_object_path });1148 try positionals.append(.{ .path = comp.tsan_lib.?.full_object_path });
1149 }1149 }
11501150
1151 // libc1151 // libc
...@@ -1603,7 +1603,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {...@@ -1603,7 +1603,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
1603 }1603 }
16041604
1605 if (comp.config.any_sanitize_thread) {1605 if (comp.config.any_sanitize_thread) {
1606 try argv.append(comp.tsan_static_lib.?.full_object_path);1606 try argv.append(comp.tsan_lib.?.full_object_path);
1607 }1607 }
16081608
1609 // libc1609 // libc
...@@ -2610,7 +2610,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, prog_node: std.Progress.Node) !void...@@ -2610,7 +2610,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, prog_node: std.Progress.Node) !void
2610 }2610 }
26112611
2612 if (comp.config.any_sanitize_thread) {2612 if (comp.config.any_sanitize_thread) {
2613 try argv.append(comp.tsan_static_lib.?.full_object_path);2613 try argv.append(comp.tsan_lib.?.full_object_path);
2614 }2614 }
26152615
2616 // libc2616 // libc
src/link/MachO.zig+17-6
...@@ -192,7 +192,7 @@ pub fn createEmpty(...@@ -192,7 +192,7 @@ pub fn createEmpty(
192 null192 null
193 else193 else
194 try std.fmt.allocPrint(arena, "{s}.o", .{emit.sub_path});194 try std.fmt.allocPrint(arena, "{s}.o", .{emit.sub_path});
195 const allow_shlib_undefined = options.allow_shlib_undefined orelse comp.config.any_sanitize_thread;195 const allow_shlib_undefined = options.allow_shlib_undefined orelse false;
196196
197 const self = try arena.create(MachO);197 const self = try arena.create(MachO);
198 self.* = .{198 self.* = .{
...@@ -413,7 +413,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: std.Progress.Node)...@@ -413,7 +413,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: std.Progress.Node)
413413
414 // TSAN414 // TSAN
415 if (comp.config.any_sanitize_thread) {415 if (comp.config.any_sanitize_thread) {
416 try positionals.append(.{ .path = comp.tsan_static_lib.?.full_object_path });416 try positionals.append(.{ .path = comp.tsan_lib.?.full_object_path });
417 }417 }
418418
419 for (positionals.items) |obj| {419 for (positionals.items) |obj| {
...@@ -831,7 +831,9 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {...@@ -831,7 +831,9 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
831 }831 }
832832
833 if (comp.config.any_sanitize_thread) {833 if (comp.config.any_sanitize_thread) {
834 try argv.append(comp.tsan_static_lib.?.full_object_path);834 const path = comp.tsan_lib.?.full_object_path;
835 try argv.append(path);
836 try argv.appendSlice(&.{ "-rpath", std.fs.path.dirname(path) orelse "." });
835 }837 }
836838
837 for (self.lib_dirs) |lib_dir| {839 for (self.lib_dirs) |lib_dir| {
...@@ -2959,7 +2961,8 @@ pub fn writeStrtab(self: *MachO, off: u32) !u32 {...@@ -2959,7 +2961,8 @@ pub fn writeStrtab(self: *MachO, off: u32) !u32 {
2959}2961}
29602962
2961fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {2963fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
2962 const gpa = self.base.comp.gpa;2964 const comp = self.base.comp;
2965 const gpa = comp.gpa;
2963 const needed_size = try load_commands.calcLoadCommandsSize(self, false);2966 const needed_size = try load_commands.calcLoadCommandsSize(self, false);
2964 const buffer = try gpa.alloc(u8, needed_size);2967 const buffer = try gpa.alloc(u8, needed_size);
2965 defer gpa.free(buffer);2968 defer gpa.free(buffer);
...@@ -3015,8 +3018,16 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {...@@ -3015,8 +3018,16 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
3015 ncmds += 1;3018 ncmds += 1;
3016 }3019 }
30173020
3018 try load_commands.writeRpathLCs(self.base.rpath_list, writer);3021 for (self.base.rpath_list) |rpath| {
3019 ncmds += self.base.rpath_list.len;3022 try load_commands.writeRpathLC(rpath, writer);
3023 ncmds += 1;
3024 }
3025 if (comp.config.any_sanitize_thread) {
3026 const path = comp.tsan_lib.?.full_object_path;
3027 const rpath = std.fs.path.dirname(path) orelse ".";
3028 try load_commands.writeRpathLC(rpath, writer);
3029 ncmds += 1;
3030 }
30203031
3021 try writer.writeStruct(macho.source_version_command{ .version = 0 });3032 try writer.writeStruct(macho.source_version_command{ .version = 0 });
3022 ncmds += 1;3033 ncmds += 1;
src/link/MachO/load_commands.zig+29-19
...@@ -18,6 +18,9 @@ fn calcInstallNameLen(cmd_size: u64, name: []const u8, assume_max_path_len: bool...@@ -18,6 +18,9 @@ fn calcInstallNameLen(cmd_size: u64, name: []const u8, assume_max_path_len: bool
18}18}
1919
20pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32 {20pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32 {
21 const comp = macho_file.base.comp;
22 const gpa = comp.gpa;
23
21 var sizeofcmds: u64 = 0;24 var sizeofcmds: u64 = 0;
2225
23 // LC_SEGMENT_6426 // LC_SEGMENT_64
...@@ -48,7 +51,6 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32...@@ -48,7 +51,6 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32
48 }51 }
49 // LC_ID_DYLIB52 // LC_ID_DYLIB
50 if (macho_file.base.isDynLib()) {53 if (macho_file.base.isDynLib()) {
51 const gpa = macho_file.base.comp.gpa;
52 const emit = macho_file.base.emit;54 const emit = macho_file.base.emit;
53 const install_name = macho_file.install_name orelse55 const install_name = macho_file.install_name orelse
54 try emit.directory.join(gpa, &.{emit.sub_path});56 try emit.directory.join(gpa, &.{emit.sub_path});
...@@ -68,6 +70,16 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32...@@ -68,6 +70,16 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32
68 assume_max_path_len,70 assume_max_path_len,
69 );71 );
70 }72 }
73
74 if (comp.config.any_sanitize_thread) {
75 const path = comp.tsan_lib.?.full_object_path;
76 const rpath = std.fs.path.dirname(path) orelse ".";
77 sizeofcmds += calcInstallNameLen(
78 @sizeOf(macho.rpath_command),
79 rpath,
80 assume_max_path_len,
81 );
82 }
71 }83 }
72 // LC_SOURCE_VERSION84 // LC_SOURCE_VERSION
73 sizeofcmds += @sizeOf(macho.source_version_command);85 sizeofcmds += @sizeOf(macho.source_version_command);
...@@ -245,24 +257,22 @@ pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void {...@@ -245,24 +257,22 @@ pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void {
245 }, writer);257 }, writer);
246}258}
247259
248pub fn writeRpathLCs(rpaths: []const []const u8, writer: anytype) !void {260pub fn writeRpathLC(rpath: []const u8, writer: anytype) !void {
249 for (rpaths) |rpath| {261 const rpath_len = rpath.len + 1;
250 const rpath_len = rpath.len + 1;262 const cmdsize = @as(u32, @intCast(mem.alignForward(
251 const cmdsize = @as(u32, @intCast(mem.alignForward(263 u64,
252 u64,264 @sizeOf(macho.rpath_command) + rpath_len,
253 @sizeOf(macho.rpath_command) + rpath_len,265 @sizeOf(u64),
254 @sizeOf(u64),266 )));
255 )));267 try writer.writeStruct(macho.rpath_command{
256 try writer.writeStruct(macho.rpath_command{268 .cmdsize = cmdsize,
257 .cmdsize = cmdsize,269 .path = @sizeOf(macho.rpath_command),
258 .path = @sizeOf(macho.rpath_command),270 });
259 });271 try writer.writeAll(rpath);
260 try writer.writeAll(rpath);272 try writer.writeByte(0);
261 try writer.writeByte(0);273 const padding = cmdsize - @sizeOf(macho.rpath_command) - rpath_len;
262 const padding = cmdsize - @sizeOf(macho.rpath_command) - rpath_len;274 if (padding > 0) {
263 if (padding > 0) {275 try writer.writeByteNTimes(0, padding);
264 try writer.writeByteNTimes(0, padding);
265 }
266 }276 }
267}277}
268278