mirror of
https://github.com/N64Recomp/N64Recomp.git
synced 2026-07-14 15:51:13 -05:00
Fix out-of-bounds read when naming reloc types beyond the o32 table
reloc_names has 8 entries (R_MIPS_NONE..R_MIPS_GPREL16), but reloc.type is set from the raw ELF r_type, so relocatable/PIC inputs carrying GOT16 / CALL16 / GPREL32 / ... (types >= 8) index past the end. reloc_names[type] is then an out-of-bounds std::vector read (UB): benign on some libstdc++ builds, but on the Windows STL it returns a garbage std::string whose huge size makes fmt's format buffer throw std::bad_alloc mid-write, aborting the recompiler after most output is already written (and truncating it). Add a bounds-checked reloc_type_name() that maps out-of-range types to R_MIPS_NONE, and use it at both call sites (dump_context and the overlay reloc table writer). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
ffb39cdad1
commit
a940efa0bb
15
src/main.cpp
15
src/main.cpp
|
|
@ -158,6 +158,17 @@ std::vector<std::string> reloc_names {
|
|||
"R_MIPS_GPREL16",
|
||||
};
|
||||
|
||||
// reloc_names only covers the basic o32 relocation types (0..7). A relocatable/PIC input can carry higher
|
||||
// types (GOT16, CALL16, GPREL32, ...) whose numeric value indexes past the end of reloc_names. Indexing the
|
||||
// vector directly is then an out-of-bounds read (undefined behavior) — harmless on some libstdc++ builds,
|
||||
// but on the Windows STL it returns a garbage std::string whose enormous size makes fmt's format buffer
|
||||
// throw std::bad_alloc mid-write, killing the recompiler after it has written most of its output. Treat any
|
||||
// out-of-range type as R_MIPS_NONE (which is also how scripts/fix-recompiled.sh normalizes these entries).
|
||||
static const std::string& reloc_type_name(N64Recomp::RelocType type) {
|
||||
size_t idx = static_cast<size_t>(type);
|
||||
return idx < reloc_names.size() ? reloc_names[idx] : reloc_names[0];
|
||||
}
|
||||
|
||||
void dump_context(const N64Recomp::Context& context, const std::unordered_map<uint16_t, std::vector<N64Recomp::DataSymbol>>& data_syms, const std::filesystem::path& func_path, const std::filesystem::path& data_path) {
|
||||
std::ofstream func_context_file {func_path};
|
||||
std::ofstream data_context_file {data_path};
|
||||
|
|
@ -211,7 +222,7 @@ void dump_context(const N64Recomp::Context& context, const std::unordered_map<ui
|
|||
fmt::print(func_context_file, "relocs = [\n");
|
||||
for (const N64Recomp::Reloc& reloc : sorted_relocs) {
|
||||
fmt::print(func_context_file, " {{ type = \"{}\", vram = 0x{:08X}, target_vram = 0x{:08X} }},\n",
|
||||
reloc_names[static_cast<int>(reloc.type)], reloc.address, reloc.target_section_offset + section.ram_addr);
|
||||
reloc_type_name(reloc.type), reloc.address, reloc.target_section_offset + section.ram_addr);
|
||||
}
|
||||
fmt::print(func_context_file, "]\n\n");
|
||||
}
|
||||
|
|
@ -996,7 +1007,7 @@ int main(int argc, char** argv) {
|
|||
target_section_offset = reloc.target_section_offset;
|
||||
}
|
||||
fmt::print(overlay_file, " {{ .offset = 0x{:08X}, .target_section_offset = 0x{:08X}, .target_section = {}, .type = {} }}, \n",
|
||||
reloc.address - section.ram_addr, target_section_offset, reloc.target_section, reloc_names[static_cast<size_t>(reloc.type)] );
|
||||
reloc.address - section.ram_addr, target_section_offset, reloc.target_section, reloc_type_name(reloc.type) );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user