fix(relinker): reject layouts that would discard exception metadata

This commit is contained in:
boykopovar 2026-10-13 10:53:32 +03:00
parent 37e25a2a78
commit 5e5eba8922
2 changed files with 10 additions and 8 deletions

View File

@ -3,7 +3,7 @@
#include <domain/Types.hpp>
#include <algorithm>
#include <cstdint>
#include <iostream>
#include <limits>
#include <string>
#include <vector>
@ -148,8 +148,7 @@ std::uint16_t ProgramHeaderLayoutBuilder::WriteLayout(
const bool keepFrames = kept.size() + kSyntheticProgramHeaderCount <= request.PhNum;
if (!keepFrames && frameCount > 0) {
std::erase_if(kept, [](const Domain::ProgramHeader& ph) { return ph.Type == PT_GNU_EH_FRAME; });
std::cerr << "WARNING: No free program header slot for PT_GNU_EH_FRAME; C++ exceptions thrown in the executable cannot be caught.\n";
throw Domain::RelinkerException("No free program header slot for PT_GNU_EH_FRAME");
}
_sortLoadHeaders(kept);

View File

@ -96,11 +96,13 @@ def main():
assert elf[offset:offset + size] == image[offset:offset + size], "eh_frame_hdr bytes changed"
assert all(header[0] != PT_SCE_VERSION for header in headers), headers
result, elf = relink(relinker, directory, "full-slots", fixture(6))
headers = program_headers(elf)
assert all(header[0] != PT_GNU_EH_FRAME for header in headers), headers
assert len(headers) == 6, headers
source = Path(directory) / "full-slots.elf"
output = Path(directory) / "full-slots.out"
source.write_bytes(fixture(6))
result = subprocess.run([str(relinker), "--skip-sce-module", str(source), str(output)], capture_output=True, text=True, timeout=20)
assert result.returncode == 2, result
assert "No free program header slot for PT_GNU_EH_FRAME" in result.stderr, result.stderr
assert not output.exists(), "Executable written without exception metadata"
image = fixture(6, with_frame=False)
table_end = 64 + 6 * 56
@ -119,7 +121,8 @@ def main():
source.write_bytes(image)
result = subprocess.run([str(relinker), "--skip-sce-module", str(source), str(output)], capture_output=True, text=True, timeout=20)
assert result.returncode == 2, (result.returncode, result.stdout, result.stderr)
assert "Not enough program header slots: need 6, available 5" in result.stderr, result.stderr
expected = "No free program header slot for PT_GNU_EH_FRAME" if with_frame else "Not enough program header slots: need 6, available 5"
assert expected in result.stderr, result.stderr
assert not output.exists(), "Insufficient program header slots must not produce an executable"
assert source.read_bytes() == image, "Input changed while rejecting insufficient program header slots"