mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
macho: reinstate duplicate definition checking
This commit is contained in:
parent
d19aab2e87
commit
34f34dbe32
@ -26,6 +26,7 @@ resolver: SymbolResolver = .{},
|
||||
/// This table will be populated after `scanRelocs` has run.
|
||||
/// Key is symbol index.
|
||||
undefs: std.AutoHashMapUnmanaged(SymbolResolver.Index, std.ArrayListUnmanaged(Ref)) = .{},
|
||||
dupes: std.AutoHashMapUnmanaged(SymbolResolver.Index, std.ArrayListUnmanaged(File.Index)) = .{},
|
||||
|
||||
dyld_info_cmd: macho.dyld_info_command = .{},
|
||||
symtab_cmd: macho.symtab_command = .{},
|
||||
@ -311,6 +312,13 @@ pub fn deinit(self: *MachO) void {
|
||||
}
|
||||
self.undefs.deinit(gpa);
|
||||
}
|
||||
{
|
||||
var it = self.dupes.iterator();
|
||||
while (it.next()) |entry| {
|
||||
entry.value_ptr.deinit(gpa);
|
||||
}
|
||||
self.dupes.deinit(gpa);
|
||||
}
|
||||
|
||||
self.symtab.deinit(gpa);
|
||||
self.strtab.deinit(gpa);
|
||||
@ -518,14 +526,13 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
|
||||
try dead_strip.gcAtoms(self);
|
||||
}
|
||||
|
||||
// TODO
|
||||
// self.checkDuplicates() catch |err| switch (err) {
|
||||
// error.HasDuplicates => return error.FlushFailure,
|
||||
// else => |e| {
|
||||
// try self.reportUnexpectedError("unexpected error while checking for duplicate symbol definitions", .{});
|
||||
// return e;
|
||||
// },
|
||||
// };
|
||||
self.checkDuplicates() catch |err| switch (err) {
|
||||
error.HasDuplicates => return error.FlushFailure,
|
||||
else => |e| {
|
||||
try self.reportUnexpectedError("unexpected error while checking for duplicate symbol definitions", .{});
|
||||
return e;
|
||||
},
|
||||
};
|
||||
|
||||
self.markImportsAndExports();
|
||||
self.deadStripDylibs();
|
||||
@ -1434,25 +1441,16 @@ fn claimUnresolved(self: *MachO) void {
|
||||
}
|
||||
|
||||
fn checkDuplicates(self: *MachO) !void {
|
||||
const gpa = self.base.comp.gpa;
|
||||
|
||||
var dupes = std.AutoArrayHashMap(Symbol.Index, std.ArrayListUnmanaged(File.Index)).init(gpa);
|
||||
defer {
|
||||
for (dupes.values()) |*list| {
|
||||
list.deinit(gpa);
|
||||
}
|
||||
dupes.deinit();
|
||||
}
|
||||
|
||||
if (self.getZigObject()) |zo| {
|
||||
try zo.checkDuplicates(&dupes, self);
|
||||
try zo.asFile().checkDuplicates(self);
|
||||
}
|
||||
|
||||
for (self.objects.items) |index| {
|
||||
try self.getFile(index).?.object.checkDuplicates(&dupes, self);
|
||||
try self.getFile(index).?.checkDuplicates(self);
|
||||
}
|
||||
|
||||
try self.reportDuplicates(dupes);
|
||||
if (self.getInternalObject()) |obj| {
|
||||
try obj.asFile().checkDuplicates(self);
|
||||
}
|
||||
try self.reportDuplicates();
|
||||
}
|
||||
|
||||
fn markImportsAndExports(self: *MachO) void {
|
||||
@ -3737,22 +3735,23 @@ pub fn reportUnexpectedError(self: *MachO, comptime format: []const u8, args: an
|
||||
try err.addNote(self, "please report this as a linker bug on https://github.com/ziglang/zig/issues/new/choose", .{});
|
||||
}
|
||||
|
||||
fn reportDuplicates(self: *MachO, dupes: anytype) error{ HasDuplicates, OutOfMemory }!void {
|
||||
fn reportDuplicates(self: *MachO) error{ HasDuplicates, OutOfMemory }!void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
const max_notes = 3;
|
||||
|
||||
var has_dupes = false;
|
||||
var it = dupes.iterator();
|
||||
var it = self.dupes.iterator();
|
||||
while (it.next()) |entry| {
|
||||
const sym = self.getSymbol(entry.key_ptr.*);
|
||||
const sym = self.resolver.keys.items[entry.key_ptr.* - 1];
|
||||
const notes = entry.value_ptr.*;
|
||||
const nnotes = @min(notes.items.len, max_notes) + @intFromBool(notes.items.len > max_notes);
|
||||
|
||||
var err = try self.addErrorWithNotes(nnotes + 1);
|
||||
try err.addMsg(self, "duplicate symbol definition: {s}", .{sym.getName(self)});
|
||||
try err.addNote(self, "defined by {}", .{sym.getFile(self).?.fmtPath()});
|
||||
has_dupes = true;
|
||||
|
||||
var inote: usize = 0;
|
||||
while (inote < @min(notes.items.len, max_notes)) : (inote += 1) {
|
||||
@ -3764,10 +3763,7 @@ fn reportDuplicates(self: *MachO, dupes: anytype) error{ HasDuplicates, OutOfMem
|
||||
const remaining = notes.items.len - max_notes;
|
||||
try err.addNote(self, "defined {d} more times", .{remaining});
|
||||
}
|
||||
|
||||
has_dupes = true;
|
||||
}
|
||||
|
||||
if (has_dupes) return error.HasDuplicates;
|
||||
}
|
||||
|
||||
@ -4452,6 +4448,11 @@ pub const SymbolResolver = struct {
|
||||
return ref.getSymbol(macho_file).?.getName(macho_file);
|
||||
}
|
||||
|
||||
pub fn getFile(key: Key, macho_file: *MachO) ?File {
|
||||
const ref = Ref{ .index = key.index, .file = key.file };
|
||||
return ref.getFile(macho_file);
|
||||
}
|
||||
|
||||
fn eql(key: Key, other: Key, macho_file: *MachO) bool {
|
||||
const key_name = key.getName(macho_file);
|
||||
const other_name = other.getName(macho_file);
|
||||
|
||||
@ -1550,25 +1550,6 @@ pub fn mergeSymbolVisibility(self: *Object, macho_file: *MachO) void {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
// pub fn checkDuplicates(self: *Object, dupes: anytype, macho_file: *MachO) error{OutOfMemory}!void {
|
||||
// for (self.symbols.items, 0..) |index, nlist_idx| {
|
||||
// const sym = macho_file.getSymbol(index);
|
||||
// if (sym.visibility != .global) continue;
|
||||
// const file = sym.getFile(macho_file) orelse continue;
|
||||
// if (file.getIndex() == self.index) continue;
|
||||
|
||||
// const nlist = self.symtab.items(.nlist)[nlist_idx];
|
||||
// if (!nlist.undf() and !nlist.tentative() and !(nlist.weakDef() or nlist.pext())) {
|
||||
// const gop = try dupes.getOrPut(index);
|
||||
// if (!gop.found_existing) {
|
||||
// gop.value_ptr.* = .{};
|
||||
// }
|
||||
// try gop.value_ptr.append(macho_file.base.comp.gpa, self.index);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
pub fn scanRelocs(self: *Object, macho_file: *MachO) !void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
@ -308,25 +308,6 @@ pub fn mergeSymbolVisibility(self: *ZigObject, macho_file: *MachO) void {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
// pub fn checkDuplicates(self: *ZigObject, dupes: anytype, macho_file: *MachO) !void {
|
||||
// for (self.symbols.items, 0..) |index, nlist_idx| {
|
||||
// const sym = macho_file.getSymbol(index);
|
||||
// if (sym.visibility != .global) continue;
|
||||
// const file = sym.getFile(macho_file) orelse continue;
|
||||
// if (file.getIndex() == self.index) continue;
|
||||
|
||||
// const nlist = self.symtab.items(.nlist)[nlist_idx];
|
||||
// if (!nlist.undf() and !nlist.tentative() and !(nlist.weakDef() or nlist.pext())) {
|
||||
// const gop = try dupes.getOrPut(index);
|
||||
// if (!gop.found_existing) {
|
||||
// gop.value_ptr.* = .{};
|
||||
// }
|
||||
// try gop.value_ptr.append(macho_file.base.comp.gpa, self.index);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
pub fn resolveLiterals(self: *ZigObject, lp: *MachO.LiteralPool, macho_file: *MachO) !void {
|
||||
_ = self;
|
||||
_ = lp;
|
||||
|
||||
@ -24,7 +24,7 @@ pub const File = union(enum) {
|
||||
_ = options;
|
||||
switch (file) {
|
||||
.zig_object => |x| try writer.writeAll(x.path),
|
||||
.internal => try writer.writeAll(""),
|
||||
.internal => try writer.writeAll("internal"),
|
||||
.object => |x| try writer.print("{}", .{x.fmtPath()}),
|
||||
.dylib => |x| try writer.writeAll(x.path),
|
||||
}
|
||||
@ -57,7 +57,7 @@ pub const File = union(enum) {
|
||||
weak: bool = false,
|
||||
tentative: bool = false,
|
||||
}) u32 {
|
||||
if (file == .object and !args.archive) {
|
||||
if (file != .dylib and !args.archive) {
|
||||
const base: u32 = blk: {
|
||||
if (args.tentative) break :blk 3;
|
||||
break :blk if (args.weak) 2 else 1;
|
||||
@ -254,6 +254,28 @@ pub const File = union(enum) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn checkDuplicates(file: File, macho_file: *MachO) !void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
const gpa = macho_file.base.comp.gpa;
|
||||
|
||||
for (file.getSymbols(), file.getNlists(), 0..) |sym, nlist, i| {
|
||||
if (sym.visibility != .global) continue;
|
||||
if (sym.flags.weak) continue;
|
||||
if (nlist.undf()) continue;
|
||||
const ref = file.getSymbolRef(@intCast(i), macho_file);
|
||||
const ref_file = ref.getFile(macho_file) orelse continue;
|
||||
if (ref_file.getIndex() == file.getIndex()) continue;
|
||||
|
||||
const gop = try macho_file.dupes.getOrPut(gpa, file.getGlobals()[i]);
|
||||
if (!gop.found_existing) {
|
||||
gop.value_ptr.* = .{};
|
||||
}
|
||||
try gop.value_ptr.append(gpa, file.getIndex());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn initOutputSections(file: File, macho_file: *MachO) !void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
@ -30,6 +30,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {
|
||||
|
||||
// Exercise linker with LLVM backend
|
||||
macho_step.dependOn(testDeadStrip(b, .{ .target = default_target }));
|
||||
macho_step.dependOn(testDuplicateDefinitions(b, .{ .target = default_target }));
|
||||
macho_step.dependOn(testEmptyObject(b, .{ .target = default_target }));
|
||||
macho_step.dependOn(testEmptyZig(b, .{ .target = default_target }));
|
||||
macho_step.dependOn(testEntryPoint(b, .{ .target = default_target }));
|
||||
@ -182,6 +183,37 @@ fn testDeadStrip(b: *Build, opts: Options) *Step {
|
||||
return test_step;
|
||||
}
|
||||
|
||||
fn testDuplicateDefinitions(b: *Build, opts: Options) *Step {
|
||||
const test_step = addTestStep(b, "duplicate-definitions", opts);
|
||||
|
||||
const obj = addObject(b, opts, .{ .name = "a", .zig_source_bytes =
|
||||
\\var x: usize = 1;
|
||||
\\export fn strong() void { x += 1; }
|
||||
\\export fn weak() void { x += 1; }
|
||||
});
|
||||
|
||||
const exe = addExecutable(b, opts, .{ .name = "main", .zig_source_bytes =
|
||||
\\var x: usize = 1;
|
||||
\\export fn strong() void { x += 1; }
|
||||
\\comptime { @export(weakImpl, .{ .name = "weak", .linkage = .weak }); }
|
||||
\\fn weakImpl() callconv(.C) void { x += 1; }
|
||||
\\extern fn weak() void;
|
||||
\\pub fn main() void {
|
||||
\\ weak();
|
||||
\\ strong();
|
||||
\\}
|
||||
});
|
||||
exe.addObject(obj);
|
||||
|
||||
expectLinkErrors(exe, test_step, .{ .exact = &.{
|
||||
"error: duplicate symbol definition: _strong",
|
||||
"note: defined by /?/a.o",
|
||||
"note: defined by /?/main.o",
|
||||
} });
|
||||
|
||||
return test_step;
|
||||
}
|
||||
|
||||
fn testDeadStripDylibs(b: *Build, opts: Options) *Step {
|
||||
const test_step = addTestStep(b, "dead-strip-dylibs", opts);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user