authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-06-10 17:55:17-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-06-10 17:55:17-07:00
log6bf529dc381cb2f5a83c5f9e303ffdab7779ac4d
tree260738d5e702421ba7f368f3bfd31898ddc35367
parent3c3bc5af29a5fcd1daaf8d8d39625c7b505e80bf

link/wasm: fix writing past the end of debug info buffer

The function `writeDbgInfoNopsBuffered` was based on the function `pwriteDbgInfoNops`, originally written by me, and then modified to write to a memory buffer instead of an open file. When writing to a file, any extra bytes beyond the end of the file extend the size of the file, and the function body of `pwriteDbgInfoNops` takes advantage of this when `next_padding_bytes` causes the write to go beyond the end of the file. However, when writing to a memory buffer, the underlying array list must be expanded if the write would cause the buffer to expand.

1 files changed, 28 insertions(+), 26 deletions(-)

src/link/Dwarf.zig+28-26
...@@ -352,6 +352,7 @@ pub const DeclState = struct {...@@ -352,6 +352,7 @@ pub const DeclState = struct {
352 const fields = ty.structFields();352 const fields = ty.structFields();
353 for (fields.keys()) |field_name, field_index| {353 for (fields.keys()) |field_name, field_index| {
354 const field = fields.get(field_name).?;354 const field = fields.get(field_name).?;
355 if (!field.ty.hasRuntimeBits()) continue;
355 // DW.AT.member356 // DW.AT.member
356 try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2);357 try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2);
357 dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_member));358 dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_member));
...@@ -1037,6 +1038,7 @@ pub fn commitDeclState(...@@ -1037,6 +1038,7 @@ pub fn commitDeclState(
1037 }1038 }
1038 }1039 }
10391040
1041 log.debug("updateDeclDebugInfoAllocation for '{s}'", .{decl.name});
1040 try self.updateDeclDebugInfoAllocation(file, atom, @intCast(u32, dbg_info_buffer.items.len));1042 try self.updateDeclDebugInfoAllocation(file, atom, @intCast(u32, dbg_info_buffer.items.len));
10411043
1042 while (decl_state.abbrev_relocs.popOrNull()) |reloc| {1044 while (decl_state.abbrev_relocs.popOrNull()) |reloc| {
...@@ -1098,6 +1100,7 @@ pub fn commitDeclState(...@@ -1098,6 +1100,7 @@ pub fn commitDeclState(
1098 }1100 }
1099 }1101 }
11001102
1103 log.debug("writeDeclDebugInfo for '{s}", .{decl.name});
1101 try self.writeDeclDebugInfo(file, atom, dbg_info_buffer.items);1104 try self.writeDeclDebugInfo(file, atom, dbg_info_buffer.items);
1102}1105}
11031106
...@@ -1141,7 +1144,10 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *Atom, len: u3...@@ -1141,7 +1144,10 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *Atom, len: u3
1141 },1144 },
1142 .wasm => {1145 .wasm => {
1143 const wasm_file = file.cast(File.Wasm).?;1146 const wasm_file = file.cast(File.Wasm).?;
1144 writeDbgInfoNopsBuffered(wasm_file.debug_info.items, atom.off, 0, &.{0}, atom.len, false);1147 const segment_index = try wasm_file.getDebugInfoIndex();
1148 const segment = &wasm_file.segments.items[segment_index];
1149 const offset = segment.offset + atom.off;
1150 try writeDbgInfoNopsToArrayList(gpa, &wasm_file.debug_info, offset, 0, &.{0}, atom.len, false);
1145 },1151 },
1146 else => unreachable,1152 else => unreachable,
1147 }1153 }
...@@ -1283,8 +1289,12 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co...@@ -1283,8 +1289,12 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co
1283 debug_info.items.len = needed_size;1289 debug_info.items.len = needed_size;
1284 }1290 }
1285 const offset = segment.offset + atom.off;1291 const offset = segment.offset + atom.off;
1286 writeDbgInfoNopsBuffered(1292 log.debug(" writeDbgInfoNopsToArrayList debug_info_len={d} offset={d} content_len={d} next_padding_size={d}", .{
1287 debug_info.items,1293 debug_info.items.len, offset, dbg_info_buf.len, next_padding_size,
1294 });
1295 try writeDbgInfoNopsToArrayList(
1296 gpa,
1297 debug_info,
1288 offset,1298 offset,
1289 prev_padding_size,1299 prev_padding_size,
1290 dbg_info_buf,1300 dbg_info_buf,
...@@ -1678,7 +1688,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u6...@@ -1678,7 +1688,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u6
1678 },1688 },
1679 .wasm => {1689 .wasm => {
1680 const wasm_file = file.cast(File.Wasm).?;1690 const wasm_file = file.cast(File.Wasm).?;
1681 writeDbgInfoNopsBuffered(wasm_file.debug_info.items, 0, 0, di_buf.items, jmp_amt, false);1691 try writeDbgInfoNopsToArrayList(self.allocator, &wasm_file.debug_info, 0, 0, di_buf.items, jmp_amt, false);
1682 },1692 },
1683 else => unreachable,1693 else => unreachable,
1684 }1694 }
...@@ -1884,35 +1894,25 @@ fn pwriteDbgInfoNops(...@@ -1884,35 +1894,25 @@ fn pwriteDbgInfoNops(
1884 try file.pwritevAll(vecs[0..vec_index], offset - prev_padding_size);1894 try file.pwritevAll(vecs[0..vec_index], offset - prev_padding_size);
1885}1895}
18861896
1887fn writeDbgInfoNopsBuffered(1897fn writeDbgInfoNopsToArrayList(
1888 buf: []u8,1898 gpa: Allocator,
1899 buffer: *std.ArrayListUnmanaged(u8),
1889 offset: u32,1900 offset: u32,
1890 prev_padding_size: usize,1901 prev_padding_size: usize,
1891 content: []const u8,1902 content: []const u8,
1892 next_padding_size: usize,1903 next_padding_size: usize,
1893 trailing_zero: bool,1904 trailing_zero: bool,
1894) void {1905) Allocator.Error!void {
1895 assert(buf.len >= content.len + prev_padding_size + next_padding_size + @boolToInt(trailing_zero));1906 try buffer.resize(gpa, @maximum(
1896 const tracy = trace(@src());1907 buffer.items.len,
1897 defer tracy.end();1908 offset + content.len + next_padding_size + 1,
18981909 ));
1899 {1910 mem.set(u8, buffer.items[offset - prev_padding_size .. offset], @enumToInt(AbbrevKind.pad1));
1900 var padding_left = prev_padding_size;1911 mem.copy(u8, buffer.items[offset..], content);
1901 while (padding_left > 0) : (padding_left -= 1) {1912 mem.set(u8, buffer.items[offset + content.len ..][0..next_padding_size], @enumToInt(AbbrevKind.pad1));
1902 buf[offset - padding_left] = @enumToInt(AbbrevKind.pad1);
1903 }
1904 }
1905
1906 mem.copy(u8, buf[offset..], content);
1907 {
1908 var padding_left = next_padding_size;
1909 while (padding_left > 0) : (padding_left -= 1) {
1910 buf[offset + content.len + padding_left] = @enumToInt(AbbrevKind.pad1);
1911 }
1912 }
19131913
1914 if (trailing_zero) {1914 if (trailing_zero) {
1915 buf[offset + content.len + next_padding_size] = 0;1915 buffer.items[offset + content.len + next_padding_size] = 0;
1916 }1916 }
1917}1917}
19181918
...@@ -2249,7 +2249,9 @@ pub fn flushModule(self: *Dwarf, file: *File, module: *Module) !void {...@@ -2249,7 +2249,9 @@ pub fn flushModule(self: *Dwarf, file: *File, module: *Module) !void {
2249 try addDbgInfoErrorSet(arena, module, error_ty, self.target, &dbg_info_buffer);2249 try addDbgInfoErrorSet(arena, module, error_ty, self.target, &dbg_info_buffer);
22502250
2251 try self.managed_atoms.append(gpa, atom);2251 try self.managed_atoms.append(gpa, atom);
2252 log.debug("updateDeclDebugInfoAllocation in flushModule", .{});
2252 try self.updateDeclDebugInfoAllocation(file, atom, @intCast(u32, dbg_info_buffer.items.len));2253 try self.updateDeclDebugInfoAllocation(file, atom, @intCast(u32, dbg_info_buffer.items.len));
2254 log.debug("writeDeclDebugInfo in flushModule", .{});
2253 try self.writeDeclDebugInfo(file, atom, dbg_info_buffer.items);2255 try self.writeDeclDebugInfo(file, atom, dbg_info_buffer.items);
22542256
2255 const file_pos = blk: {2257 const file_pos = blk: {