Skip to content

Commit 45143c6

Browse files
committed
MachO: emit absolute path in N_OSO stabs
This path being relative is unconventional and causes issues for us if the output artifact is ever used from a different cwd than the one it was built from. The behavior implemented by this commit of always emitting these paths as absolute was actually the behavior in 0.14.x, but it regressed in 0.15.1 due to internal reworks to path handling which led to relative paths being more common in the compiler internals. Resolves: #25433
1 parent d629a14 commit 45143c6

File tree

4 files changed

+58
-65
lines changed

4 files changed

+58
-65
lines changed

src/link/MachO.zig

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -919,7 +919,16 @@ fn addObject(self: *MachO, path: Path, handle: File.HandleIndex, offset: u64) !v
919919
const tracy = trace(@src());
920920
defer tracy.end();
921921

922-
const gpa = self.base.comp.gpa;
922+
const comp = self.base.comp;
923+
const gpa = comp.gpa;
924+
925+
const abs_path = try std.fs.path.resolvePosix(gpa, &.{
926+
comp.dirs.cwd,
927+
path.root_dir.path orelse ".",
928+
path.sub_path,
929+
});
930+
errdefer gpa.free(abs_path);
931+
923932
const mtime: u64 = mtime: {
924933
const file = self.getFileHandle(handle);
925934
const stat = file.stat() catch break :mtime 0;
@@ -928,10 +937,7 @@ fn addObject(self: *MachO, path: Path, handle: File.HandleIndex, offset: u64) !v
928937
const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
929938
self.files.set(index, .{ .object = .{
930939
.offset = offset,
931-
.path = .{
932-
.root_dir = path.root_dir,
933-
.sub_path = try gpa.dupe(u8, path.sub_path),
934-
},
940+
.path = abs_path,
935941
.file_handle = handle,
936942
.mtime = mtime,
937943
.index = index,

src/link/MachO/Archive.zig

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ pub fn deinit(self: *Archive, allocator: Allocator) void {
55
}
66

77
pub fn unpack(self: *Archive, macho_file: *MachO, path: Path, handle_index: File.HandleIndex, fat_arch: ?fat.Arch) !void {
8-
const gpa = macho_file.base.comp.gpa;
9-
const diags = &macho_file.base.comp.link_diags;
8+
const comp = macho_file.base.comp;
9+
const gpa = comp.gpa;
10+
const diags = &comp.link_diags;
1011

1112
var arena = std.heap.ArenaAllocator.init(gpa);
1213
defer arena.deinit();
@@ -55,23 +56,30 @@ pub fn unpack(self: *Archive, macho_file: *MachO, path: Path, handle_index: File
5556
mem.eql(u8, name, SYMDEF_SORTED) or
5657
mem.eql(u8, name, SYMDEF64_SORTED)) continue;
5758

59+
const abs_path = try std.fs.path.resolvePosix(gpa, &.{
60+
comp.dirs.cwd,
61+
path.root_dir.path orelse ".",
62+
path.sub_path,
63+
});
64+
errdefer gpa.free(abs_path);
65+
66+
const o_basename = try gpa.dupe(u8, name);
67+
errdefer gpa.free(o_basename);
68+
5869
const object: Object = .{
5970
.offset = pos,
6071
.in_archive = .{
61-
.path = .{
62-
.root_dir = path.root_dir,
63-
.sub_path = try gpa.dupe(u8, path.sub_path),
64-
},
72+
.path = abs_path,
6573
.size = hdr_size,
6674
},
67-
.path = Path.initCwd(try gpa.dupe(u8, name)),
75+
.path = o_basename,
6876
.file_handle = handle_index,
6977
.index = undefined,
7078
.alive = false,
7179
.mtime = hdr.date() catch 0,
7280
};
7381

74-
log.debug("extracting object '{f}' from archive '{f}'", .{ object.path, path });
82+
log.debug("extracting object '{s}' from archive '{f}'", .{ o_basename, path });
7583

7684
try self.objects.append(gpa, object);
7785
}

src/link/MachO/Object.zig

Lines changed: 30 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
/// Non-zero for fat object files or archives
22
offset: u64,
3-
/// Archive files cannot contain subdirectories, so only the basename is needed
4-
/// for output. However, the full path is kept for error reporting.
5-
path: Path,
3+
/// If `in_archive` is not `null`, this is the basename of the object in the archive. Otherwise,
4+
/// this is a fully-resolved absolute path, because that is the path we need to embed in stabs to
5+
/// ensure the output does not depend on its cwd.
6+
path: []u8,
67
file_handle: File.HandleIndex,
78
mtime: u64,
89
index: File.Index,
@@ -41,8 +42,8 @@ output_symtab_ctx: MachO.SymtabCtx = .{},
4142
output_ar_state: Archive.ArState = .{},
4243

4344
pub fn deinit(self: *Object, allocator: Allocator) void {
44-
if (self.in_archive) |*ar| allocator.free(ar.path.sub_path);
45-
allocator.free(self.path.sub_path);
45+
if (self.in_archive) |*ar| allocator.free(ar.path);
46+
allocator.free(self.path);
4647
for (self.sections.items(.relocs), self.sections.items(.subsections)) |*relocs, *sub| {
4748
relocs.deinit(allocator);
4849
sub.deinit(allocator);
@@ -1703,7 +1704,7 @@ pub fn updateArSize(self: *Object, macho_file: *MachO) !void {
17031704
pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writer: anytype) !void {
17041705
// Header
17051706
const size = try macho_file.cast(usize, self.output_ar_state.size);
1706-
const basename = std.fs.path.basename(self.path.sub_path);
1707+
const basename = std.fs.path.basename(self.path);
17071708
try Archive.writeHeader(basename, size, ar_format, writer);
17081709
// Data
17091710
const file = macho_file.getFileHandle(self.file_handle);
@@ -1756,12 +1757,7 @@ pub fn calcSymtabSize(self: *Object, macho_file: *MachO) void {
17561757
self.calcStabsSize(macho_file);
17571758
}
17581759

1759-
fn pathLen(path: Path) usize {
1760-
// +1 for the path separator
1761-
return (if (path.root_dir.path) |p| p.len + @intFromBool(path.sub_path.len != 0) else 0) + path.sub_path.len;
1762-
}
1763-
1764-
pub fn calcStabsSize(self: *Object, macho_file: *MachO) void {
1760+
fn calcStabsSize(self: *Object, macho_file: *MachO) void {
17651761
if (self.compile_unit) |cu| {
17661762
const comp_dir = cu.getCompDir(self.*);
17671763
const tu_name = cu.getTuName(self.*);
@@ -1771,9 +1767,11 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) void {
17711767
self.output_symtab_ctx.strsize += @as(u32, @intCast(tu_name.len + 1)); // tu_name
17721768

17731769
if (self.in_archive) |ar| {
1774-
self.output_symtab_ctx.strsize += @intCast(pathLen(ar.path) + 1 + self.path.basename().len + 1 + 1);
1770+
// "/path/to/archive.a(object.o)\x00"
1771+
self.output_symtab_ctx.strsize += @intCast(ar.path.len + self.path.len + 3);
17751772
} else {
1776-
self.output_symtab_ctx.strsize += @intCast(pathLen(self.path) + 1);
1773+
// "/path/to/object.o\x00"
1774+
self.output_symtab_ctx.strsize += @intCast(self.path.len + 1);
17771775
}
17781776

17791777
for (self.symbols.items, 0..) |sym, i| {
@@ -2018,7 +2016,7 @@ pub fn writeSymtab(self: Object, macho_file: *MachO, ctx: anytype) void {
20182016
self.writeStabs(n_strx, macho_file, ctx);
20192017
}
20202018

2021-
pub fn writeStabs(self: Object, stroff: u32, macho_file: *MachO, ctx: anytype) void {
2019+
fn writeStabs(self: Object, stroff: u32, macho_file: *MachO, ctx: anytype) void {
20222020
const writeFuncStab = struct {
20232021
inline fn writeFuncStab(
20242022
n_strx: u32,
@@ -2103,38 +2101,20 @@ pub fn writeStabs(self: Object, stroff: u32, macho_file: *MachO, ctx: anytype) v
21032101
};
21042102
index += 1;
21052103
if (self.in_archive) |ar| {
2106-
if (ar.path.root_dir.path) |p| {
2107-
@memcpy(ctx.strtab.items[n_strx..][0..p.len], p);
2108-
n_strx += @intCast(p.len);
2109-
if (ar.path.sub_path.len != 0) {
2110-
ctx.strtab.items[n_strx] = '/';
2111-
n_strx += 1;
2112-
}
2113-
}
2114-
@memcpy(ctx.strtab.items[n_strx..][0..ar.path.sub_path.len], ar.path.sub_path);
2115-
n_strx += @intCast(ar.path.sub_path.len);
2116-
ctx.strtab.items[n_strx] = '(';
2117-
n_strx += 1;
2118-
const basename = self.path.basename();
2119-
@memcpy(ctx.strtab.items[n_strx..][0..basename.len], basename);
2120-
n_strx += @intCast(basename.len);
2121-
ctx.strtab.items[n_strx] = ')';
2122-
n_strx += 1;
2123-
ctx.strtab.items[n_strx] = 0;
2104+
// "/path/to/archive.a(object.o)\x00"
2105+
@memcpy(ctx.strtab.items[n_strx..][0..ar.path.len], ar.path);
2106+
n_strx += @intCast(ar.path.len);
2107+
ctx.strtab.items[n_strx..][0] = '(';
21242108
n_strx += 1;
2109+
@memcpy(ctx.strtab.items[n_strx..][0..self.path.len], self.path);
2110+
n_strx += @intCast(self.path.len);
2111+
ctx.strtab.items[n_strx..][0..2].* = ")\x00".*;
2112+
n_strx += 2;
21252113
} else {
2126-
if (self.path.root_dir.path) |p| {
2127-
@memcpy(ctx.strtab.items[n_strx..][0..p.len], p);
2128-
n_strx += @intCast(p.len);
2129-
if (self.path.sub_path.len != 0) {
2130-
ctx.strtab.items[n_strx] = '/';
2131-
n_strx += 1;
2132-
}
2133-
}
2134-
@memcpy(ctx.strtab.items[n_strx..][0..self.path.sub_path.len], self.path.sub_path);
2135-
n_strx += @intCast(self.path.sub_path.len);
2136-
ctx.strtab.items[n_strx] = 0;
2137-
n_strx += 1;
2114+
// "/path/to/object.o\x00"
2115+
@memcpy(ctx.strtab.items[n_strx..][0..self.path.len], self.path);
2116+
ctx.strtab.items[n_strx..][self.path.len] = 0;
2117+
n_strx += @intCast(self.path.len + 1);
21382118
}
21392119

21402120
for (self.symbols.items, 0..) |sym, i| {
@@ -2621,11 +2601,9 @@ pub fn fmtPath(self: Object) std.fmt.Alt(Object, formatPath) {
26212601

26222602
fn formatPath(object: Object, w: *Writer) Writer.Error!void {
26232603
if (object.in_archive) |ar| {
2624-
try w.print("{f}({s})", .{
2625-
ar.path, object.path.basename(),
2626-
});
2604+
try w.print("{s}({s})", .{ ar.path, object.path });
26272605
} else {
2628-
try w.print("{f}", .{object.path});
2606+
try w.writeAll(object.path);
26292607
}
26302608
}
26312609

@@ -2716,7 +2694,9 @@ const CompileUnit = struct {
27162694
};
27172695

27182696
const InArchive = struct {
2719-
path: Path,
2697+
/// This is a fully-resolved absolute path, because that is the path we need to embed in stabs
2698+
/// to ensure the output does not depend on its cwd.
2699+
path: []u8,
27202700
size: u32,
27212701
};
27222702

@@ -3094,7 +3074,6 @@ const log = std.log.scoped(.link);
30943074
const macho = std.macho;
30953075
const math = std.math;
30963076
const mem = std.mem;
3097-
const Path = std.Build.Cache.Path;
30983077
const Allocator = std.mem.Allocator;
30993078
const Writer = std.Io.Writer;
31003079

src/link/MachO/relocatable.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
191191
pos = mem.alignForward(usize, pos, 2);
192192
state.file_off = pos;
193193
pos += @sizeOf(Archive.ar_hdr);
194-
pos += mem.alignForward(usize, o.path.basename().len + 1, ptr_width);
194+
pos += mem.alignForward(usize, std.fs.path.basename(o.path).len + 1, ptr_width);
195195
pos += try macho_file.cast(usize, state.size);
196196
},
197197
else => unreachable,

0 commit comments

Comments
 (0)