From fe13b4d2df589fb15c2a4cebcfc165e8a178ed09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A0?= Date: Sat, 31 Oct 2026 03:55:09 +0100 Subject: [PATCH] test(relinker): pin EH sdata4 funcrel signed overflow row Standalone EH table fixture after the unwind record loop: CIE zPLR with LSDA encoding 0x4B (sdata4 funcrel), FDE augmentation 0xFFFFEFFF with functionBase at the FDE begin 0x1000. The signed branch of EhFrameReader::encoded must reject it with "unwind pointer address overflowed". Co-Authored-By: Claude Haiku 5.5 --- .../tests/UnwindRecordBoundsTests.cpp | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/core/relinker/relinker/tests/UnwindRecordBoundsTests.cpp b/core/relinker/relinker/tests/UnwindRecordBoundsTests.cpp index 042b064711..f4278597a6 100644 --- a/core/relinker/relinker/tests/UnwindRecordBoundsTests.cpp +++ b/core/relinker/relinker/tests/UnwindRecordBoundsTests.cpp @@ -4,6 +4,7 @@ #include #include #include +#include static void Require(bool ok) { if (!ok) throw std::runtime_error("Unwind record validation failed"); } @@ -146,6 +147,35 @@ int main() { sdata8Rejected = std::string(error.what()).find("unwind pointer address overflowed") != std::string::npos; } Require(sdata8Rejected); - std::cout << "21 unwind record cases passed\n"; + std::vector lsdaBytes(0x400, 0); + Io::WriteU32(lsdaBytes, 0x200, 25); + lsdaBytes[0x208] = 1; + const std::uint8_t ciePrefix[] = {'z', 'P', 'L', 'R', 0, 1, 0, 0x78, 11, 0}; + std::copy(std::begin(ciePrefix), std::end(ciePrefix), lsdaBytes.begin() + 0x209); + lsdaBytes[0x212] = 0; + Io::WriteU64(lsdaBytes, 0x213, 0x1000); + lsdaBytes[0x21B] = 0x4B; + lsdaBytes[0x21C] = 0; + Io::WriteU32(lsdaBytes, 0x220, 29); + Io::WriteU32(lsdaBytes, 0x224, 0x24); + Io::WriteU64(lsdaBytes, 0x228, 0x1000); + Io::WriteU64(lsdaBytes, 0x230, 0x20); + lsdaBytes[0x238] = 4; + Io::WriteU32(lsdaBytes, 0x239, 0xFFFFEFFF); + lsdaBytes[0x300] = 1; + lsdaBytes[0x302] = 3; + Io::WriteU64(lsdaBytes, 0x304, 0x200); + Io::WriteU32(lsdaBytes, 0x30C, 1); + Io::WriteU64(lsdaBytes, 0x310, 0x1000); + Io::WriteU64(lsdaBytes, 0x318, 0x220); + Domain::ProgramHeader lsdaLoad{}; lsdaLoad.Type = 1; lsdaLoad.Flags = 4; lsdaLoad.FileSize = lsdaBytes.size(); lsdaLoad.MemorySize = lsdaBytes.size(); lsdaLoad.Alignment = 8; + Domain::ProgramHeader lsdaEh = lsdaLoad; lsdaEh.Type = 0x6474E550; lsdaEh.Offset = 0x300; lsdaEh.MappedAddress = 0x300; lsdaEh.FileSize = 32; lsdaEh.MemorySize = 32; lsdaEh.Alignment = 4; + bool lsdaOverflowRejected = false; + try { Relinker::UnusedNidFilter::ReadExceptionFunctions(lsdaBytes, {lsdaLoad, lsdaEh}, {}, {}); } + catch (const Domain::RelinkerException& error) { + lsdaOverflowRejected = std::string(error.what()).find("unwind pointer address overflowed") != std::string::npos; + } + Require(lsdaOverflowRejected); + std::cout << "22 unwind record cases passed\n"; } catch (const std::exception& error) { std::cerr << error.what() << '\n'; return 1; } }