authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-01-14 19:20:11+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-01-14 20:39:00+01:00
log7a96907b9233cd1385472a03ff75530d3a02556f
tree6ab7e0ca09fb13cbde775f282a381dbbf03de5ff
parent89d4ac628959fe301ee93b88fdc66ab1988d5f33

elf: check for and report duplicate symbol definitions


3 files changed, 97 insertions(+), 15 deletions(-)

src/link/Elf.zig+56
......@@ -1323,6 +1323,11 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node)
13231323 }
13241324 }
13251325
1326 self.checkDuplicates() catch |err| switch (err) {
1327 error.HasDuplicates => return error.FlushFailure,
1328 else => |e| return e,
1329 };
1330
13261331 try self.initOutputSections();
13271332 try self.addLinkerDefinedSymbols();
13281333 self.claimUnresolved();
......@@ -3491,6 +3496,27 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {
34913496 }
34923497}
34933498
3499fn checkDuplicates(self: *Elf) !void {
3500 const gpa = self.base.comp.gpa;
3501
3502 var dupes = std.AutoArrayHashMap(Symbol.Index, std.ArrayListUnmanaged(File.Index)).init(gpa);
3503 defer {
3504 for (dupes.values()) |*list| {
3505 list.deinit(gpa);
3506 }
3507 dupes.deinit();
3508 }
3509
3510 if (self.zigObjectPtr()) |zig_object| {
3511 try zig_object.checkDuplicates(&dupes, self);
3512 }
3513 for (self.objects.items) |index| {
3514 try self.file(index).?.object.checkDuplicates(&dupes, self);
3515 }
3516
3517 try self.reportDuplicates(dupes);
3518}
3519
34943520fn initOutputSections(self: *Elf) !void {
34953521 for (self.objects.items) |index| {
34963522 try self.file(index).?.object.initOutputSections(self);
......@@ -6164,6 +6190,36 @@ fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void {
61646190 }
61656191}
61666192
6193fn reportDuplicates(self: *Elf, dupes: anytype) error{ HasDuplicates, OutOfMemory }!void {
6194 const max_notes = 3;
6195 var has_dupes = false;
6196 var it = dupes.iterator();
6197 while (it.next()) |entry| {
6198 const sym = self.symbol(entry.key_ptr.*);
6199 const notes = entry.value_ptr.*;
6200 const nnotes = @min(notes.items.len, max_notes) + @intFromBool(notes.items.len > max_notes);
6201
6202 var err = try self.addErrorWithNotes(nnotes + 1);
6203 try err.addMsg(self, "duplicate symbol definition: {s}", .{sym.name(self)});
6204 try err.addNote(self, "defined by {}", .{sym.file(self).?.fmtPath()});
6205
6206 var inote: usize = 0;
6207 while (inote < @min(notes.items.len, max_notes)) : (inote += 1) {
6208 const file_ptr = self.file(notes.items[inote]).?;
6209 try err.addNote(self, "defined by {}", .{file_ptr.fmtPath()});
6210 }
6211
6212 if (notes.items.len > max_notes) {
6213 const remaining = notes.items.len - max_notes;
6214 try err.addNote(self, "defined {d} more times", .{remaining});
6215 }
6216
6217 has_dupes = true;
6218 }
6219
6220 if (has_dupes) return error.HasDuplicates;
6221}
6222
61676223fn reportMissingLibraryError(
61686224 self: *Elf,
61696225 checked_paths: []const []const u8,
src/link/Elf/Object.zig+15-15
......@@ -581,30 +581,30 @@ pub fn markEhFrameAtomsDead(self: Object, elf_file: *Elf) void {
581581 }
582582}
583583
584pub fn checkDuplicates(self: *Object, elf_file: *Elf) void {
584pub fn checkDuplicates(self: *Object, dupes: anytype, elf_file: *Elf) error{OutOfMemory}!void {
585585 const first_global = self.first_global orelse return;
586586 for (self.globals(), 0..) |index, i| {
587 const sym_idx = @as(u32, @intCast(first_global + i));
588 const this_sym = self.symtab.items[sym_idx];
587 const sym_idx = first_global + i;
588 const sym = self.symtab.items[sym_idx];
589589 const global = elf_file.symbol(index);
590 const global_file = global.getFile(elf_file) orelse continue;
590 const global_file = global.file(elf_file) orelse continue;
591591
592 if (self.index == global_file.getIndex() or
593 this_sym.st_shndx == elf.SHN_UNDEF or
594 this_sym.st_bind() == elf.STB_WEAK or
595 this_sym.st_shndx == elf.SHN_COMMON) continue;
592 if (self.index == global_file.index() or
593 sym.st_shndx == elf.SHN_UNDEF or
594 sym.st_bind() == elf.STB_WEAK or
595 sym.st_shndx == elf.SHN_COMMON) continue;
596596
597 if (this_sym.st_shndx != elf.SHN_ABS) {
598 const atom_index = self.atoms.items[this_sym.st_shndx];
597 if (sym.st_shndx != elf.SHN_ABS) {
598 const atom_index = self.atoms.items[sym.st_shndx];
599599 const atom = elf_file.atom(atom_index) orelse continue;
600600 if (!atom.flags.alive) continue;
601601 }
602602
603 elf_file.base.fatal("multiple definition: {}: {}: {s}", .{
604 self.fmtPath(),
605 global_file.fmtPath(),
606 global.getName(elf_file),
607 });
603 const gop = try dupes.getOrPut(index);
604 if (!gop.found_existing) {
605 gop.value_ptr.* = .{};
606 }
607 try gop.value_ptr.append(elf_file.base.comp.gpa, self.index);
608608 }
609609}
610610
src/link/Elf/ZigObject.zig+26
......@@ -451,6 +451,32 @@ pub fn markLive(self: *ZigObject, elf_file: *Elf) void {
451451 }
452452}
453453
454pub fn checkDuplicates(self: *ZigObject, dupes: anytype, elf_file: *Elf) error{OutOfMemory}!void {
455 for (self.globals(), 0..) |index, i| {
456 const esym = self.global_esyms.items(.elf_sym)[i];
457 const shndx = self.global_esyms.items(.shndx)[i];
458 const global = elf_file.symbol(index);
459 const global_file = global.file(elf_file) orelse continue;
460
461 if (self.index == global_file.index() or
462 esym.st_shndx == elf.SHN_UNDEF or
463 esym.st_bind() == elf.STB_WEAK or
464 esym.st_shndx == elf.SHN_COMMON) continue;
465
466 if (esym.st_shndx == SHN_ATOM) {
467 const atom_index = self.atoms.items[shndx];
468 const atom = elf_file.atom(atom_index) orelse continue;
469 if (!atom.flags.alive) continue;
470 }
471
472 const gop = try dupes.getOrPut(index);
473 if (!gop.found_existing) {
474 gop.value_ptr.* = .{};
475 }
476 try gop.value_ptr.append(elf_file.base.comp.gpa, self.index);
477 }
478}
479
454480/// This is just a temporary helper function that allows us to re-read what we wrote to file into a buffer.
455481/// We need this so that we can write to an archive.
456482/// TODO implement writing ZigObject data directly to a buffer instead.