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...@@ -2310,11 +2310,11 @@ fn shiftLocalsByOffset(self: *MachO, match: MatchingSection, offset: i64) !void
2310 var atom = self.atoms.get(match) orelse return;2310 var atom = self.atoms.get(match) orelse return;
23112311
2312 while (true) {2312 while (true) {
2313 const atom_sym = &self.locals.items[atom.sym_index];2313 const atom_sym = atom.getSymbolPtr(self);
2314 atom_sym.n_value = @intCast(u64, @intCast(i64, atom_sym.n_value) + offset);2314 atom_sym.n_value = @intCast(u64, @intCast(i64, atom_sym.n_value) + offset);
23152315
2316 for (atom.contained.items) |sym_at_off| {2316 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 });
2318 contained_sym.n_value = @intCast(u64, @intCast(i64, contained_sym.n_value) + offset);2318 contained_sym.n_value = @intCast(u64, @intCast(i64, contained_sym.n_value) + offset);
2319 }2319 }
23202320
...@@ -3488,7 +3488,7 @@ fn shrinkAtom(self: *MachO, atom: *Atom, new_block_size: u64, match: MatchingSec...@@ -3488,7 +3488,7 @@ fn shrinkAtom(self: *MachO, atom: *Atom, new_block_size: u64, match: MatchingSec
3488}3488}
34893489
3490fn growAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, match: MatchingSection) !u64 {3490fn 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);
3492 const align_ok = mem.alignBackwardGeneric(u64, sym.n_value, alignment) == sym.n_value;3492 const align_ok = mem.alignBackwardGeneric(u64, sym.n_value, alignment) == sym.n_value;
3493 const need_realloc = !align_ok or new_atom_size > atom.capacity(self);3493 const need_realloc = !align_ok or new_atom_size > atom.capacity(self);
3494 if (!need_realloc) return sym.n_value;3494 if (!need_realloc) return sym.n_value;
...@@ -3643,14 +3643,14 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv...@@ -3643,14 +3643,14 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv
3643 },3643 },
3644 }3644 }
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
3648 if (decl_state) |*ds| {3648 if (decl_state) |*ds| {
3649 try self.d_sym.?.dwarf.commitDeclState(3649 try self.d_sym.?.dwarf.commitDeclState(
3650 &self.base,3650 &self.base,
3651 module,3651 module,
3652 decl,3652 decl,
3653 symbol.n_value,3653 addr,
3654 decl.link.macho.size,3654 decl.link.macho.size,
3655 ds,3655 ds,
3656 );3656 );
...@@ -3731,7 +3731,7 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu...@@ -3731,7 +3731,7 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu
37313731
3732 errdefer self.freeAtom(atom, match, true);3732 errdefer self.freeAtom(atom, match, true);
37333733
3734 const symbol = &self.locals.items[atom.sym_index];3734 const symbol = atom.getSymbolPtr(self);
3735 symbol.* = .{3735 symbol.* = .{
3736 .n_strx = name_str_index,3736 .n_strx = name_str_index,
3737 .n_type = macho.N_SECT,3737 .n_type = macho.N_SECT,
...@@ -3814,14 +3814,14 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)...@@ -3814,14 +3814,14 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)
3814 },3814 },
3815 }3815 }
3816 };3816 };
3817 const symbol = try self.placeDecl(decl_index, code.len);3817 const addr = try self.placeDecl(decl_index, code.len);
38183818
3819 if (decl_state) |*ds| {3819 if (decl_state) |*ds| {
3820 try self.d_sym.?.dwarf.commitDeclState(3820 try self.d_sym.?.dwarf.commitDeclState(
3821 &self.base,3821 &self.base,
3822 module,3822 module,
3823 decl,3823 decl,
3824 symbol.n_value,3824 addr,
3825 decl.link.macho.size,3825 decl.link.macho.size,
3826 ds,3826 ds,
3827 );3827 );
...@@ -3977,12 +3977,11 @@ fn getMatchingSectionAtom(...@@ -3977,12 +3977,11 @@ fn getMatchingSectionAtom(
3977 return match;3977 return match;
3978}3978}
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 {
3981 const module = self.base.options.module.?;3981 const module = self.base.options.module.?;
3982 const decl = module.declPtr(decl_index);3982 const decl = module.declPtr(decl_index);
3983 const required_alignment = decl.getAlignment(self.base.options.target);3983 const required_alignment = decl.getAlignment(self.base.options.target);
3984 assert(decl.link.macho.sym_index != 0); // Caller forgot to call allocateDeclIndexes()3984 assert(decl.link.macho.sym_index != 0); // Caller forgot to call allocateDeclIndexes()
3985 const symbol = &self.locals.items[decl.link.macho.sym_index];
39863985
3987 const sym_name = try decl.getFullyQualifiedName(module);3986 const sym_name = try decl.getFullyQualifiedName(module);
3988 defer self.base.allocator.free(sym_name);3987 defer self.base.allocator.free(sym_name);
...@@ -4000,6 +3999,7 @@ fn placeDecl(self: *MachO, decl_index: Module.Decl.Index, code_len: usize) !*mac...@@ -4000,6 +3999,7 @@ fn placeDecl(self: *MachO, decl_index: Module.Decl.Index, code_len: usize) !*mac
4000 const match = decl_ptr.*.?;3999 const match = decl_ptr.*.?;
40014000
4002 if (decl.link.macho.size != 0) {4001 if (decl.link.macho.size != 0) {
4002 const symbol = decl.link.macho.getSymbolPtr(self);
4003 const capacity = decl.link.macho.capacity(self);4003 const capacity = decl.link.macho.capacity(self);
4004 const need_realloc = code_len > capacity or !mem.isAlignedGeneric(u64, symbol.n_value, required_alignment);4004 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...@@ -4033,6 +4033,7 @@ fn placeDecl(self: *MachO, decl_index: Module.Decl.Index, code_len: usize) !*mac
40334033
4034 errdefer self.freeAtom(&decl.link.macho, match, false);4034 errdefer self.freeAtom(&decl.link.macho, match, false);
40354035
4036 const symbol = decl.link.macho.getSymbolPtr(self);
4036 symbol.* = .{4037 symbol.* = .{
4037 .n_strx = name_str_index,4038 .n_strx = name_str_index,
4038 .n_type = macho.N_SECT,4039 .n_type = macho.N_SECT,
...@@ -4047,7 +4048,7 @@ fn placeDecl(self: *MachO, decl_index: Module.Decl.Index, code_len: usize) !*mac...@@ -4047,7 +4048,7 @@ fn placeDecl(self: *MachO, decl_index: Module.Decl.Index, code_len: usize) !*mac
4047 self.got_entries.items[got_index].sym_index = got_atom.sym_index;4048 self.got_entries.items[got_index].sym_index = got_atom.sym_index;
4048 }4049 }
40494050
4050 return symbol;4051 return decl.link.macho.getSymbol(self).n_value;
4051}4052}
40524053
4053pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl: *const Module.Decl) !void {4054pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl: *const Module.Decl) !void {
...@@ -5233,7 +5234,7 @@ fn allocateAtom(...@@ -5233,7 +5234,7 @@ fn allocateAtom(
5233 const big_atom = free_list.items[i];5234 const big_atom = free_list.items[i];
5234 // We now have a pointer to a live atom that has too much capacity.5235 // We now have a pointer to a live atom that has too much capacity.
5235 // Is it enough that we could fit this new atom?5236 // 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);
5237 const capacity = big_atom.capacity(self);5238 const capacity = big_atom.capacity(self);
5238 const ideal_capacity = if (needs_padding) padToIdeal(capacity) else capacity;5239 const ideal_capacity = if (needs_padding) padToIdeal(capacity) else capacity;
5239 const ideal_capacity_end_vaddr = math.add(u64, sym.n_value, ideal_capacity) catch ideal_capacity;5240 const ideal_capacity_end_vaddr = math.add(u64, sym.n_value, ideal_capacity) catch ideal_capacity;
...@@ -5264,7 +5265,7 @@ fn allocateAtom(...@@ -5264,7 +5265,7 @@ fn allocateAtom(
5264 }5265 }
5265 break :blk new_start_vaddr;5266 break :blk new_start_vaddr;
5266 } else if (self.atoms.get(match)) |last| {5267 } else if (self.atoms.get(match)) |last| {
5267 const last_symbol = self.locals.items[last.sym_index];5268 const last_symbol = last.getSymbol(self);
5268 const ideal_capacity = if (needs_padding) padToIdeal(last.size) else last.size;5269 const ideal_capacity = if (needs_padding) padToIdeal(last.size) else last.size;
5269 const ideal_capacity_end_vaddr = last_symbol.n_value + ideal_capacity;5270 const ideal_capacity_end_vaddr = last_symbol.n_value + ideal_capacity;
5270 const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, alignment);5271 const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, alignment);