authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-07-23 00:13:32+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-07-23 00:13:34+02:00
logcf6cfc830db89e0031200d1a16c93eb7801cb911
tree5aba192c62931ba6a4cafa5e80aafa4d1cac2d20
parent600348283fa5ea9646f91997e0a32f4632ca30b8

macho: fix use-after-move in placeDecl

Previously, we would get a pointer to a slot in the symbol table, apply changes to the symbol, and return the pointer. This however didn't take into account that the symbol table may be moved in memory in-between the modification and return from the function (`fn placeDecl`). Prior to my rewrite, this was not possible within the body of the said function. However, my rewrite revamped how we allocate GOT atoms and their matching symtab indexes, which now may cause a move in memory of the container.

1 files changed, 14 insertions(+), 13 deletions(-)

src/link/MachO.zig+14-13
......@@ -2310,11 +2310,11 @@ fn shiftLocalsByOffset(self: *MachO, match: MatchingSection, offset: i64) !void
23102310 var atom = self.atoms.get(match) orelse return;
23112311
23122312 while (true) {
2313 const atom_sym = &self.locals.items[atom.sym_index];
2313 const atom_sym = atom.getSymbolPtr(self);
23142314 atom_sym.n_value = @intCast(u64, @intCast(i64, atom_sym.n_value) + offset);
23152315
23162316 for (atom.contained.items) |sym_at_off| {
2317 const contained_sym = &self.locals.items[sym_at_off.sym_index];
2317 const contained_sym = self.getSymbolPtr(.{ .sym_index = sym_at_off.sym_index, .file = atom.file });
23182318 contained_sym.n_value = @intCast(u64, @intCast(i64, contained_sym.n_value) + offset);
23192319 }
23202320
......@@ -3488,7 +3488,7 @@ fn shrinkAtom(self: *MachO, atom: *Atom, new_block_size: u64, match: MatchingSec
34883488}
34893489
34903490fn growAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, match: MatchingSection) !u64 {
3491 const sym = self.locals.items[atom.sym_index];
3491 const sym = atom.getSymbol(self);
34923492 const align_ok = mem.alignBackwardGeneric(u64, sym.n_value, alignment) == sym.n_value;
34933493 const need_realloc = !align_ok or new_atom_size > atom.capacity(self);
34943494 if (!need_realloc) return sym.n_value;
......@@ -3643,14 +3643,14 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv
36433643 },
36443644 }
36453645
3646 const symbol = try self.placeDecl(decl_index, decl.link.macho.code.items.len);
3646 const addr = try self.placeDecl(decl_index, decl.link.macho.code.items.len);
36473647
36483648 if (decl_state) |*ds| {
36493649 try self.d_sym.?.dwarf.commitDeclState(
36503650 &self.base,
36513651 module,
36523652 decl,
3653 symbol.n_value,
3653 addr,
36543654 decl.link.macho.size,
36553655 ds,
36563656 );
......@@ -3731,7 +3731,7 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu
37313731
37323732 errdefer self.freeAtom(atom, match, true);
37333733
3734 const symbol = &self.locals.items[atom.sym_index];
3734 const symbol = atom.getSymbolPtr(self);
37353735 symbol.* = .{
37363736 .n_strx = name_str_index,
37373737 .n_type = macho.N_SECT,
......@@ -3814,14 +3814,14 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)
38143814 },
38153815 }
38163816 };
3817 const symbol = try self.placeDecl(decl_index, code.len);
3817 const addr = try self.placeDecl(decl_index, code.len);
38183818
38193819 if (decl_state) |*ds| {
38203820 try self.d_sym.?.dwarf.commitDeclState(
38213821 &self.base,
38223822 module,
38233823 decl,
3824 symbol.n_value,
3824 addr,
38253825 decl.link.macho.size,
38263826 ds,
38273827 );
......@@ -3977,12 +3977,11 @@ fn getMatchingSectionAtom(
39773977 return match;
39783978}
39793979
3980fn placeDecl(self: *MachO, decl_index: Module.Decl.Index, code_len: usize) !*macho.nlist_64 {
3980fn placeDecl(self: *MachO, decl_index: Module.Decl.Index, code_len: usize) !u64 {
39813981 const module = self.base.options.module.?;
39823982 const decl = module.declPtr(decl_index);
39833983 const required_alignment = decl.getAlignment(self.base.options.target);
39843984 assert(decl.link.macho.sym_index != 0); // Caller forgot to call allocateDeclIndexes()
3985 const symbol = &self.locals.items[decl.link.macho.sym_index];
39863985
39873986 const sym_name = try decl.getFullyQualifiedName(module);
39883987 defer self.base.allocator.free(sym_name);
......@@ -4000,6 +3999,7 @@ fn placeDecl(self: *MachO, decl_index: Module.Decl.Index, code_len: usize) !*mac
40003999 const match = decl_ptr.*.?;
40014000
40024001 if (decl.link.macho.size != 0) {
4002 const symbol = decl.link.macho.getSymbolPtr(self);
40034003 const capacity = decl.link.macho.capacity(self);
40044004 const need_realloc = code_len > capacity or !mem.isAlignedGeneric(u64, symbol.n_value, required_alignment);
40054005
......@@ -4033,6 +4033,7 @@ fn placeDecl(self: *MachO, decl_index: Module.Decl.Index, code_len: usize) !*mac
40334033
40344034 errdefer self.freeAtom(&decl.link.macho, match, false);
40354035
4036 const symbol = decl.link.macho.getSymbolPtr(self);
40364037 symbol.* = .{
40374038 .n_strx = name_str_index,
40384039 .n_type = macho.N_SECT,
......@@ -4047,7 +4048,7 @@ fn placeDecl(self: *MachO, decl_index: Module.Decl.Index, code_len: usize) !*mac
40474048 self.got_entries.items[got_index].sym_index = got_atom.sym_index;
40484049 }
40494050
4050 return symbol;
4051 return decl.link.macho.getSymbol(self).n_value;
40514052}
40524053
40534054pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl: *const Module.Decl) !void {
......@@ -5233,7 +5234,7 @@ fn allocateAtom(
52335234 const big_atom = free_list.items[i];
52345235 // We now have a pointer to a live atom that has too much capacity.
52355236 // Is it enough that we could fit this new atom?
5236 const sym = self.locals.items[big_atom.sym_index];
5237 const sym = big_atom.getSymbol(self);
52375238 const capacity = big_atom.capacity(self);
52385239 const ideal_capacity = if (needs_padding) padToIdeal(capacity) else capacity;
52395240 const ideal_capacity_end_vaddr = math.add(u64, sym.n_value, ideal_capacity) catch ideal_capacity;
......@@ -5264,7 +5265,7 @@ fn allocateAtom(
52645265 }
52655266 break :blk new_start_vaddr;
52665267 } else if (self.atoms.get(match)) |last| {
5267 const last_symbol = self.locals.items[last.sym_index];
5268 const last_symbol = last.getSymbol(self);
52685269 const ideal_capacity = if (needs_padding) padToIdeal(last.size) else last.size;
52695270 const ideal_capacity_end_vaddr = last_symbol.n_value + ideal_capacity;
52705271 const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, alignment);