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,
185185/// Populated when we build the libunwind static library. A Job to build this is placed in the queue
186186/// and resolved before calling linker.flush().
187187libunwind_static_lib: ?CRTFile = null,
188/// Populated when we build the TSAN static library. A Job to build this is placed in the queue
188/// Populated when we build the TSAN library. A Job to build this is placed in the queue
189189/// and resolved before calling linker.flush().
190tsan_static_lib: ?CRTFile = null,
190tsan_lib: ?CRTFile = null,
191191/// Populated when we build the libc static library. A Job to build this is placed in the queue
192192/// and resolved before calling linker.flush().
193193libc_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
2525 defer arena_allocator.deinit();
2626 const arena = arena_allocator.allocator();
2727
28 const root_name = "tsan";
29 const output_mode = .Lib;
30 const link_mode = .static;
3128 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;
3241 const basename = try std.zig.binNameAlloc(arena, .{
3342 .root_name = root_name,
3443 .target = target,
......@@ -43,6 +52,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
4352
4453 const optimize_mode = comp.compilerRtOptMode();
4554 const strip = comp.compilerRtStrip();
55 const link_libcpp = target.isDarwin();
4656
4757 const config = Compilation.Config.resolve(.{
4858 .output_mode = output_mode,
......@@ -54,6 +64,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
5464 .root_optimize_mode = optimize_mode,
5565 .root_strip = strip,
5666 .link_libc = true,
67 .link_libcpp = link_libcpp,
5768 }) catch |err| {
5869 comp.setMiscFailure(
5970 .libtsan,
......@@ -272,6 +283,14 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
272283 });
273284 }
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;
275294 const sub_compilation = Compilation.create(comp.gpa, arena, .{
276295 .local_cache_directory = comp.global_cache_directory,
277296 .global_cache_directory = comp.global_cache_directory,
......@@ -294,7 +313,10 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
294313 .verbose_cimport = comp.verbose_cimport,
295314 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
296315 .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,
298320 }) catch |err| {
299321 comp.setMiscFailure(
300322 .libtsan,
......@@ -317,8 +339,8 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
317339 },
318340 };
319341
320 assert(comp.tsan_static_lib == null);
321 comp.tsan_static_lib = try sub_compilation.toCrtFile();
342 assert(comp.tsan_lib == null);
343 comp.tsan_lib = try sub_compilation.toCrtFile();
322344}
323345
324346const 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
11451145
11461146 // TSAN
11471147 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 });
11491149 }
11501150
11511151 // libc
......@@ -1603,7 +1603,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
16031603 }
16041604
16051605 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);
16071607 }
16081608
16091609 // libc
......@@ -2610,7 +2610,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, prog_node: std.Progress.Node) !void
26102610 }
26112611
26122612 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);
26142614 }
26152615
26162616 // libc
src/link/MachO.zig+17-6
......@@ -192,7 +192,7 @@ pub fn createEmpty(
192192 null
193193 else
194194 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
197197 const self = try arena.create(MachO);
198198 self.* = .{
......@@ -413,7 +413,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: std.Progress.Node)
413413
414414 // TSAN
415415 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 });
417417 }
418418
419419 for (positionals.items) |obj| {
......@@ -831,7 +831,9 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
831831 }
832832
833833 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 "." });
835837 }
836838
837839 for (self.lib_dirs) |lib_dir| {
......@@ -2959,7 +2961,8 @@ pub fn writeStrtab(self: *MachO, off: u32) !u32 {
29592961}
29602962
29612963fn 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;
29632966 const needed_size = try load_commands.calcLoadCommandsSize(self, false);
29642967 const buffer = try gpa.alloc(u8, needed_size);
29652968 defer gpa.free(buffer);
......@@ -3015,8 +3018,16 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
30153018 ncmds += 1;
30163019 }
30173020
3018 try load_commands.writeRpathLCs(self.base.rpath_list, writer);
3019 ncmds += self.base.rpath_list.len;
3021 for (self.base.rpath_list) |rpath| {
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
30213032 try writer.writeStruct(macho.source_version_command{ .version = 0 });
30223033 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
1818}
1919
2020pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32 {
21 const comp = macho_file.base.comp;
22 const gpa = comp.gpa;
23
2124 var sizeofcmds: u64 = 0;
2225
2326 // LC_SEGMENT_64
......@@ -48,7 +51,6 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32
4851 }
4952 // LC_ID_DYLIB
5053 if (macho_file.base.isDynLib()) {
51 const gpa = macho_file.base.comp.gpa;
5254 const emit = macho_file.base.emit;
5355 const install_name = macho_file.install_name orelse
5456 try emit.directory.join(gpa, &.{emit.sub_path});
......@@ -68,6 +70,16 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32
6870 assume_max_path_len,
6971 );
7072 }
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 }
7183 }
7284 // LC_SOURCE_VERSION
7385 sizeofcmds += @sizeOf(macho.source_version_command);
......@@ -245,24 +257,22 @@ pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void {
245257 }, writer);
246258}
247259
248pub fn writeRpathLCs(rpaths: []const []const u8, writer: anytype) !void {
249 for (rpaths) |rpath| {
250 const rpath_len = rpath.len + 1;
251 const cmdsize = @as(u32, @intCast(mem.alignForward(
252 u64,
253 @sizeOf(macho.rpath_command) + rpath_len,
254 @sizeOf(u64),
255 )));
256 try writer.writeStruct(macho.rpath_command{
257 .cmdsize = cmdsize,
258 .path = @sizeOf(macho.rpath_command),
259 });
260 try writer.writeAll(rpath);
261 try writer.writeByte(0);
262 const padding = cmdsize - @sizeOf(macho.rpath_command) - rpath_len;
263 if (padding > 0) {
264 try writer.writeByteNTimes(0, padding);
265 }
260pub fn writeRpathLC(rpath: []const u8, writer: anytype) !void {
261 const rpath_len = rpath.len + 1;
262 const cmdsize = @as(u32, @intCast(mem.alignForward(
263 u64,
264 @sizeOf(macho.rpath_command) + rpath_len,
265 @sizeOf(u64),
266 )));
267 try writer.writeStruct(macho.rpath_command{
268 .cmdsize = cmdsize,
269 .path = @sizeOf(macho.rpath_command),
270 });
271 try writer.writeAll(rpath);
272 try writer.writeByte(0);
273 const padding = cmdsize - @sizeOf(macho.rpath_command) - rpath_len;
274 if (padding > 0) {
275 try writer.writeByteNTimes(0, padding);
266276 }
267277}
268278