diff --git a/lib/std/debug/Dwarf/Unwind.zig b/lib/std/debug/Dwarf/Unwind.zig index 5334988b90..2eaa89c404 100644 --- a/lib/std/debug/Dwarf/Unwind.zig +++ b/lib/std/debug/Dwarf/Unwind.zig @@ -433,7 +433,7 @@ pub const FrameDescriptionEntry = struct { .lsb_z => { // There is augmentation data, but it's irrelevant to us -- it // only contains the LSDA pointer, which we don't care about. - const aug_data_len = try r.takeLeb128(u64); + const aug_data_len = try r.takeLeb128(usize); _ = try r.discardAll(aug_data_len); }, } @@ -463,17 +463,20 @@ pub fn prepareLookup(unwind: *Unwind, gpa: Allocator, addr_size_bytes: u8, endia switch (try EntryHeader.read(&r, entry_offset, section.id, endian)) { .cie => |cie_info| { // Ignore CIEs for now; we'll parse them when we read a corresponding FDE - try r.discardAll(cie_info.bytes_len); + try r.discardAll(cast(usize, cie_info.bytes_len) orelse return error.EndOfStream); continue; }, .fde => |fde_info| { - var cie_r: Reader = .fixed(section.bytes[fde_info.cie_offset..]); + if (fde_info.cie_offset > section.bytes.len) return error.EndOfStream; + var cie_r: Reader = .fixed(section.bytes[@intCast(fde_info.cie_offset)..]); const cie_info = switch (try EntryHeader.read(&cie_r, fde_info.cie_offset, section.id, endian)) { .cie => |cie_info| cie_info, .fde, .terminator => return bad(), // this is meant to be a CIE }; - const cie: CommonInformationEntry = try .parse(try cie_r.take(cie_info.bytes_len), section.id, addr_size_bytes); - const fde: FrameDescriptionEntry = try .parse(section.vaddr + r.seek, try r.take(fde_info.bytes_len), cie, endian); + const cie_bytes_len = cast(usize, cie_info.bytes_len) orelse return error.EndOfStream; + const fde_bytes_len = cast(usize, fde_info.bytes_len) orelse return error.EndOfStream; + const cie: CommonInformationEntry = try .parse(try cie_r.take(cie_bytes_len), section.id, addr_size_bytes); + const fde: FrameDescriptionEntry = try .parse(section.vaddr + r.seek, try r.take(fde_bytes_len), cie, endian); try fde_list.append(gpa, .{ .pc_begin = fde.pc_begin, .fde_offset = entry_offset, @@ -537,27 +540,29 @@ pub fn lookupPc(unwind: *const Unwind, pc: u64, addr_size_bytes: u8, endian: End pub fn getFde(unwind: *const Unwind, fde_offset: u64, addr_size_bytes: u8, endian: Endian) !struct { Format, CommonInformationEntry, FrameDescriptionEntry } { const section = unwind.frame_section; - var fde_reader: Reader = .fixed(section.bytes[fde_offset..]); + if (fde_offset > section.bytes.len) return error.EndOfStream; + var fde_reader: Reader = .fixed(section.bytes[@intCast(fde_offset)..]); const fde_info = switch (try EntryHeader.read(&fde_reader, fde_offset, section.id, endian)) { .fde => |info| info, .cie, .terminator => return bad(), // This is meant to be an FDE }; const cie_offset = fde_info.cie_offset; - var cie_reader: Reader = .fixed(section.bytes[cie_offset..]); + if (cie_offset > section.bytes.len) return error.EndOfStream; + var cie_reader: Reader = .fixed(section.bytes[@intCast(cie_offset)..]); const cie_info = switch (try EntryHeader.read(&cie_reader, cie_offset, section.id, endian)) { .cie => |info| info, .fde, .terminator => return bad(), // This is meant to be a CIE }; const cie: CommonInformationEntry = try .parse( - try cie_reader.take(cie_info.bytes_len), + try cie_reader.take(cast(usize, cie_info.bytes_len) orelse return error.EndOfStream), section.id, addr_size_bytes, ); const fde: FrameDescriptionEntry = try .parse( section.vaddr + fde_offset + fde_reader.seek, - try fde_reader.take(fde_info.bytes_len), + try fde_reader.take(cast(usize, fde_info.bytes_len) orelse return error.EndOfStream), cie, endian, ); @@ -566,9 +571,8 @@ pub fn getFde(unwind: *const Unwind, fde_offset: u64, addr_size_bytes: u8, endia } const EhPointerContext = struct { - // The address of the pointer field itself + /// The address of the pointer field itself pc_rel_base: u64, - // These relative addressing modes are only used in specific cases, and // might not be available / required in all parsing contexts data_rel_base: ?u64 = null, @@ -604,7 +608,7 @@ fn readEhPointerAbs(r: *Reader, enc_ty: EH.PE.Type, addr_size_bytes: u8, endian: fn readEhPointer(r: *Reader, enc: EH.PE, addr_size_bytes: u8, ctx: EhPointerContext, endian: Endian) !u64 { const offset = try readEhPointerAbs(r, enc.type, addr_size_bytes, endian); if (enc.indirect) return bad(); // GCC extension; not supported - const base = switch (enc.rel) { + const base: u64 = switch (enc.rel) { .abs, .aligned => 0, .pcrel => ctx.pc_rel_base, .textrel => ctx.text_rel_base orelse return bad(), @@ -613,7 +617,10 @@ fn readEhPointer(r: *Reader, enc: EH.PE, addr_size_bytes: u8, ctx: EhPointerCont _ => return bad(), }; return switch (offset) { - .signed => |s| @intCast(try std.math.add(i64, s, @as(i64, @intCast(base)))), + .signed => |s| if (s >= 0) + try std.math.add(u64, base, @intCast(s)) + else + try std.math.sub(u64, base, @intCast(-s)), // absptr can actually contain signed values in some cases (aarch64 MachO) .unsigned => |u| u +% base, }; diff --git a/lib/std/debug/ElfFile.zig b/lib/std/debug/ElfFile.zig index b8f1bdf615..5be5ee55c5 100644 --- a/lib/std/debug/ElfFile.zig +++ b/lib/std/debug/ElfFile.zig @@ -19,7 +19,7 @@ strtab: ?[]const u8, symtab: ?SymtabSection, /// Binary search table lazily populated by `searchSymtab`. -symbol_search_table: ?[]u64, +symbol_search_table: ?[]usize, /// The memory-mapped ELF file, which is referenced by `dwarf`. This field is here only so that /// this memory can be unmapped by `ElfFile.deinit`. @@ -259,7 +259,7 @@ pub fn searchSymtab(ef: *ElfFile, gpa: Allocator, vaddr: u64) error{ swap_endian: bool, target: u64, symbols: []align(1) const Sym, - fn predicate(ctx: @This(), sym_index: u64) bool { + fn predicate(ctx: @This(), sym_index: usize) bool { // We need to return `true` for the first N items, then `false` for the rest -- // the index we'll get out is the first `false` one. So, we'll return `true` iff // the target address is after the *end* of this symbol. This synchronizes with @@ -270,7 +270,7 @@ pub fn searchSymtab(ef: *ElfFile, gpa: Allocator, vaddr: u64) error{ return ctx.target >= sym_end; } }; - const sym_index_index = std.sort.partitionPoint(u64, search_table, @as(SearchContext, .{ + const sym_index_index = std.sort.partitionPoint(usize, search_table, @as(SearchContext, .{ .swap_endian = swap_endian, .target = vaddr, .symbols = symbols, @@ -291,8 +291,8 @@ pub fn searchSymtab(ef: *ElfFile, gpa: Allocator, vaddr: u64) error{ fn buildSymbolSearchTable(gpa: Allocator, endian: Endian, comptime Sym: type, symbols: []align(1) const Sym) error{ OutOfMemory, BadSymtab, -}![]u64 { - var result: std.ArrayList(u64) = .empty; +}![]usize { + var result: std.ArrayList(usize) = .empty; defer result.deinit(gpa); const swap_endian = endian != @import("builtin").cpu.arch.endian(); @@ -308,7 +308,7 @@ fn buildSymbolSearchTable(gpa: Allocator, endian: Endian, comptime Sym: type, sy const SortContext = struct { swap_endian: bool, symbols: []align(1) const Sym, - fn lessThan(ctx: @This(), lhs_sym_index: u64, rhs_sym_index: u64) bool { + fn lessThan(ctx: @This(), lhs_sym_index: usize, rhs_sym_index: usize) bool { // We sort by *end* address, not start address. This matches up with logic in `searchSymtab`. var lhs_sym = ctx.symbols[lhs_sym_index]; var rhs_sym = ctx.symbols[rhs_sym_index]; @@ -321,7 +321,7 @@ fn buildSymbolSearchTable(gpa: Allocator, endian: Endian, comptime Sym: type, sy return lhs_val < rhs_val; } }; - std.mem.sort(u64, result.items, @as(SortContext, .{ + std.mem.sort(usize, result.items, @as(SortContext, .{ .swap_endian = swap_endian, .symbols = symbols, }), SortContext.lessThan); @@ -504,7 +504,7 @@ fn loadInner( continue; } - const buf = try arena.alloc(u8, ch_size); + const buf = try arena.alloc(u8, std.math.cast(usize, ch_size) orelse return error.Overflow); var fw: std.Io.Writer = .fixed(buf); var decompress: std.compress.flate.Decompress = .init(§ion_reader, .zlib, &.{}); const n = decompress.reader.streamRemaining(&fw) catch |err| switch (err) { diff --git a/lib/std/debug/SelfInfo/ElfModule.zig b/lib/std/debug/SelfInfo/ElfModule.zig index 7871f1012f..8a0acf8bb0 100644 --- a/lib/std/debug/SelfInfo/ElfModule.zig +++ b/lib/std/debug/SelfInfo/ElfModule.zig @@ -200,7 +200,7 @@ fn loadUnwindInfo(module: *const ElfModule, gpa: Allocator, di: *DebugInfo) Erro error.EndOfStream, error.Overflow => return error.InvalidDebugInfo, error.UnsupportedAddrSize => return error.UnsupportedDebugInfo, }; - buf[0] = .initEhFrameHdr(header, section_vaddr, @ptrFromInt(module.load_offset + header.eh_frame_vaddr)); + buf[0] = .initEhFrameHdr(header, section_vaddr, @ptrFromInt(@as(usize, @intCast(module.load_offset + header.eh_frame_vaddr)))); break :unwinds buf[0..1]; } else unwinds: { // There is no `.eh_frame_hdr` section. There may still be an `.eh_frame` or `.debug_frame` @@ -208,20 +208,19 @@ fn loadUnwindInfo(module: *const ElfModule, gpa: Allocator, di: *DebugInfo) Erro try module.loadElf(gpa, di); const opt_debug_frame = &di.loaded_elf.?.debug_frame; const opt_eh_frame = &di.loaded_elf.?.eh_frame; + var i: usize = 0; // If both are present, we can't just pick one -- the info could be split between them. // `.debug_frame` is likely to be the more complete section, so we'll prioritize that one. if (opt_debug_frame.*) |*debug_frame| { - buf[0] = .initSection(.debug_frame, debug_frame.vaddr, debug_frame.bytes); - if (opt_eh_frame.*) |*eh_frame| { - buf[1] = .initSection(.eh_frame, eh_frame.vaddr, eh_frame.bytes); - break :unwinds buf[0..2]; - } - break :unwinds buf[0..1]; - } else if (opt_eh_frame.*) |*eh_frame| { - buf[0] = .initSection(.eh_frame, eh_frame.vaddr, eh_frame.bytes); - break :unwinds buf[0..1]; + buf[i] = .initSection(.debug_frame, debug_frame.vaddr, debug_frame.bytes); + i += 1; } - return error.MissingDebugInfo; + if (opt_eh_frame.*) |*eh_frame| { + buf[i] = .initSection(.eh_frame, eh_frame.vaddr, eh_frame.bytes); + i += 1; + } + if (i == 0) return error.MissingDebugInfo; + break :unwinds buf[0..i]; }; errdefer for (unwinds) |*u| u.deinit(gpa); for (unwinds) |*u| try prepareUnwindLookup(u, gpa); diff --git a/lib/std/elf.zig b/lib/std/elf.zig index 43b542c09e..3b0c085003 100644 --- a/lib/std/elf.zig +++ b/lib/std/elf.zig @@ -744,7 +744,8 @@ pub const SectionHeaderBufferIterator = struct { const size: u64 = if (it.elf_header.is_64) @sizeOf(Elf64_Shdr) else @sizeOf(Elf32_Shdr); const offset = it.elf_header.shoff + size * it.index; - var reader = std.Io.Reader.fixed(it.buf[offset..]); + if (offset > it.buf.len) return error.EndOfStream; + var reader = std.Io.Reader.fixed(it.buf[@intCast(offset)..]); return takeShdr(&reader, it.elf_header); }