From e71901e79a0037be7a0503bb750ccf228cb33451 Mon Sep 17 00:00:00 2001 From: Romain Thomas Date: Sat, 10 Oct 2026 07:07:06 +0200 Subject: [PATCH] refactor: forward information to the `parse` functions instead of adding attribute --- include/LIEF/PE/ExceptionInfo.hpp | 4 ++- include/LIEF/PE/Parser.hpp | 18 ------------ .../AArch64/UnpackedFunction.hpp | 1 + .../RuntimeFunctionAArch64.hpp | 4 +-- src/PE/ExceptionInfo.cpp | 14 +++++---- src/PE/Parser.cpp | 18 ++++++++---- .../AArch64/UnpackedFunction.cpp | 29 +++++++++++-------- .../RuntimeFunctionAArch64.cpp | 6 ++-- 8 files changed, 47 insertions(+), 47 deletions(-) diff --git a/include/LIEF/PE/ExceptionInfo.hpp b/include/LIEF/PE/ExceptionInfo.hpp index bfdca02d4..19a0fb4c5 100644 --- a/include/LIEF/PE/ExceptionInfo.hpp +++ b/include/LIEF/PE/ExceptionInfo.hpp @@ -32,8 +32,10 @@ class Parser; /// This class is the base class for any exception or runtime function entry class LIEF_API ExceptionInfo { public: - static std::unique_ptr parse(Parser& ctx, BinaryStream& strm); static std::unique_ptr parse(Parser& ctx, BinaryStream& strm, + uint64_t size, uint64_t nb_scopes); + static std::unique_ptr parse(Parser& ctx, BinaryStream& strm, + uint64_t size, uint64_t nb_scopes, Header::MACHINE_TYPES arch); ExceptionInfo() = delete; diff --git a/include/LIEF/PE/Parser.hpp b/include/LIEF/PE/Parser.hpp index d143c80d1..1269d32b8 100644 --- a/include/LIEF/PE/Parser.hpp +++ b/include/LIEF/PE/Parser.hpp @@ -195,27 +195,10 @@ class LIEF_API Parser : public LIEF::Parser { std::unique_ptr stream_from_rva(uint32_t rva, size_t size = 0); - bool consume_exception_scopes(size_t count) { - if (count > exception_scopes_budget_) { - exception_scopes_budget_ = 0; - return false; - } - exception_scopes_budget_ -= count; - return true; - } - void record_relocation(uint32_t rva, span data); ok_error_t record_delta_relocation(uint32_t rva, int64_t delta, size_t size); private: - // Caps total AArch64 epilog scopes to bound allocations on a malformed table - void seed_exception_scopes_budget(size_t table_size) { - static constexpr size_t PDATA_ENTRY_SIZE = 2 * sizeof(uint32_t); - static constexpr size_t MAX_SCOPES_PER_FUNCTION = 32; - exception_scopes_budget_ = (table_size / PDATA_ENTRY_SIZE) * - MAX_SCOPES_PER_FUNCTION; - } - struct relocation_t { uint64_t size = 0; uint64_t value = 0; @@ -309,7 +292,6 @@ class LIEF_API Parser : public LIEF::Parser { std::map memoize_exception_info_; std::map dyn_hdr_relocs_; std::vector> unresolved_chains_; - size_t exception_scopes_budget_ = 0; ParserConfig config_; }; diff --git a/include/LIEF/PE/exceptions_info/AArch64/UnpackedFunction.hpp b/include/LIEF/PE/exceptions_info/AArch64/UnpackedFunction.hpp index cda76355f..062dcfd04 100644 --- a/include/LIEF/PE/exceptions_info/AArch64/UnpackedFunction.hpp +++ b/include/LIEF/PE/exceptions_info/AArch64/UnpackedFunction.hpp @@ -50,6 +50,7 @@ class LIEF_API UnpackedFunction : public RuntimeFunctionAArch64 { using it_const_epilog_scopes = const_ref_iterator; static std::unique_ptr parse(Parser& ctx, BinaryStream& strm, + uint64_t size, uint64_t nb_scopes, uint32_t xdata_rva, uint32_t rva); UnpackedFunction(uint32_t rva, uint32_t length) : diff --git a/include/LIEF/PE/exceptions_info/RuntimeFunctionAArch64.hpp b/include/LIEF/PE/exceptions_info/RuntimeFunctionAArch64.hpp index 12a34487e..8c15986e8 100644 --- a/include/LIEF/PE/exceptions_info/RuntimeFunctionAArch64.hpp +++ b/include/LIEF/PE/exceptions_info/RuntimeFunctionAArch64.hpp @@ -45,8 +45,8 @@ class LIEF_API RuntimeFunctionAArch64 : public ExceptionInfo { RESERVED = 3, }; - static std::unique_ptr parse(Parser& ctx, - BinaryStream& strm); + static std::unique_ptr + parse(Parser& ctx, BinaryStream& strm, uint64_t size, uint64_t nb_scopes); RuntimeFunctionAArch64(uint64_t RVA, uint32_t length, PACKED_FLAGS flag) : ExceptionInfo(ARCH::ARM64, RVA), diff --git a/src/PE/ExceptionInfo.cpp b/src/PE/ExceptionInfo.cpp index e2b232c1d..16c851b88 100644 --- a/src/PE/ExceptionInfo.cpp +++ b/src/PE/ExceptionInfo.cpp @@ -23,9 +23,9 @@ namespace LIEF::PE { -std::unique_ptr ExceptionInfo::parse(Parser& ctx, - BinaryStream& strm, - Header::MACHINE_TYPES arch) { +std::unique_ptr + ExceptionInfo::parse(Parser& ctx, BinaryStream& strm, uint64_t size, + uint64_t nb_scopes, Header::MACHINE_TYPES arch) { uint64_t pos = strm.pos(); switch (arch) { case Header::MACHINE_TYPES::AMD64: @@ -38,7 +38,7 @@ std::unique_ptr ExceptionInfo::parse(Parser& ctx, } case Header::MACHINE_TYPES::ARM64: { - if (auto F = RuntimeFunctionAArch64::parse(ctx, strm)) { + if (auto F = RuntimeFunctionAArch64::parse(ctx, strm, size, nb_scopes)) { F->offset(pos); return F; } @@ -51,9 +51,11 @@ std::unique_ptr ExceptionInfo::parse(Parser& ctx, } std::unique_ptr ExceptionInfo::parse(Parser& ctx, - BinaryStream& strm) { + BinaryStream& strm, + uint64_t size, + uint64_t nb_scopes) { const Header::MACHINE_TYPES arch = ctx.bin().header().machine(); - return parse(ctx, strm, arch); + return parse(ctx, strm, size, nb_scopes, arch); } } diff --git a/src/PE/Parser.cpp b/src/PE/Parser.cpp index 1591ae4b4..77913cd6c 100644 --- a/src/PE/Parser.cpp +++ b/src/PE/Parser.cpp @@ -46,6 +46,7 @@ #include "LIEF/PE/debug/PogoEntry.hpp" #include "LIEF/PE/debug/Repro.hpp" #include "LIEF/PE/debug/VCFeature.hpp" +#include "LIEF/PE/exceptions_info/AArch64/UnpackedFunction.hpp" #include "LIEF/PE/exceptions_info/RuntimeFunctionX64.hpp" #include "LIEF/PE/signature/Signature.hpp" #include "LIEF/PE/signature/SignatureParser.hpp" @@ -761,15 +762,17 @@ ok_error_t Parser::parse_exceptions() { return make_error_code(lief_errors::corrupted); } - seed_exception_scopes_budget(pdata.size()); - + uint64_t nb_scopes = 0; [[maybe_unused]] size_t idx = 0; while (*stream) { - auto ptr = ExceptionInfo::parse(*this, *stream); + auto ptr = ExceptionInfo::parse(*this, *stream, pdata.size(), nb_scopes); if (ptr == nullptr) { LIEF_INFO("Failed to parse exception info index: {}", idx); break; } + if (const auto* unpacked = ptr->as()) { + nb_scopes += unpacked->epilog_scopes().size(); + } ptr->offset(base_offset + ptr->offset()); binary_->exceptions_.push_back(std::move(ptr)); ++idx; @@ -830,8 +833,6 @@ ok_error_t Parser::parse_chpe_exceptions() { uint64_t base_offset = binary_->rva_to_offset(arm64->extra_rfe_table()); - seed_exception_scopes_budget(arm64->extra_rfe_table_size()); - Header::MACHINE_TYPES target_arch = bin().header().machine(); switch (target_arch) { // ARM64EC @@ -848,13 +849,18 @@ ok_error_t Parser::parse_chpe_exceptions() { default: break; } + uint64_t nb_scopes = 0; [[maybe_unused]] size_t idx = 0; while (*stream) { - auto ptr = ExceptionInfo::parse(*this, *stream, target_arch); + auto ptr = ExceptionInfo::parse(*this, *stream, arm64->extra_rfe_table_size(), + nb_scopes, target_arch); if (ptr == nullptr) { LIEF_INFO("Failed to parse exception info index: {}", idx); break; } + if (const auto* unpacked = ptr->as()) { + nb_scopes += unpacked->epilog_scopes().size(); + } ptr->offset(base_offset + ptr->offset()); binary_->exceptions_.push_back(std::move(ptr)); diff --git a/src/PE/exceptions_info/AArch64/UnpackedFunction.cpp b/src/PE/exceptions_info/AArch64/UnpackedFunction.cpp index 631a5c251..a4927de9c 100644 --- a/src/PE/exceptions_info/AArch64/UnpackedFunction.cpp +++ b/src/PE/exceptions_info/AArch64/UnpackedFunction.cpp @@ -13,13 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "LIEF/PE/exceptions_info/AArch64/UnpackedFunction.hpp" -#include "LIEF/BinaryStream/BinaryStream.hpp" -#include "LIEF/BinaryStream/SpanStream.hpp" -#include "LIEF/span.hpp" +#include #include -#include "LIEF/PE/Parser.hpp" +#include "LIEF/BinaryStream/BinaryStream.hpp" +#include "LIEF/BinaryStream/SpanStream.hpp" +#include "LIEF/PE/exceptions_info/AArch64/UnpackedFunction.hpp" +#include "LIEF/span.hpp" + #include "LIEF/PE/exceptions_info/internal_arm64.hpp" #include "PE/exceptions_info/UnwindAArch64Decoder.hpp" @@ -30,11 +31,16 @@ namespace LIEF::PE::unwind_aarch64 { using epilog_scope_t = UnpackedFunction::epilog_scope_t; -std::unique_ptr UnpackedFunction::parse(Parser& ctx, - BinaryStream& strm, - uint32_t xdata_rva, - uint32_t rva) { +std::unique_ptr + UnpackedFunction::parse(Parser& /*ctx*/, BinaryStream& strm, uint64_t size, + uint64_t nb_scopes, uint32_t xdata_rva, uint32_t rva) { static constexpr auto WIDTH = 20; + + static constexpr size_t PDATA_ENTRY_SIZE = 2 * sizeof(uint32_t); + static constexpr size_t MAX_SCOPES_PER_FUNCTION = 32; + + const uint64_t max_scopes = (size / PDATA_ENTRY_SIZE) * MAX_SCOPES_PER_FUNCTION; + details::arm64_unpacked_t unpacked; LIEF_DEBUG("Parsing unpacked function {:#010x}", rva); @@ -91,9 +97,8 @@ std::unique_ptr UnpackedFunction::parse(Parser& ctx, /// is required. std::vector scopes; if (unpacked.E() == 0) { - if (!ctx.consume_exception_scopes(ecount)) { - LIEF_DEBUG("Epilog scope budget exhausted (record claims {} scopes)", - ecount); + if (nb_scopes + ecount > max_scopes) { + LIEF_DEBUG("Epilog scope out of ranges (requested {} scopes)", ecount); return func; } func->epilog_scopes_offset_ = strm.pos() - strm_offset; diff --git a/src/PE/exceptions_info/RuntimeFunctionAArch64.cpp b/src/PE/exceptions_info/RuntimeFunctionAArch64.cpp index 947dc257d..f0e250c9b 100644 --- a/src/PE/exceptions_info/RuntimeFunctionAArch64.cpp +++ b/src/PE/exceptions_info/RuntimeFunctionAArch64.cpp @@ -29,7 +29,8 @@ namespace LIEF::PE { std::unique_ptr - RuntimeFunctionAArch64::parse(Parser& ctx, BinaryStream& strm) { + RuntimeFunctionAArch64::parse(Parser& ctx, BinaryStream& strm, uint64_t size, + uint64_t nb_scopes) { auto rva_start = strm.read(); if (!rva_start) { LIEF_WARN("Failed to read exception info RVA start (line: {})", __LINE__); @@ -54,7 +55,8 @@ std::unique_ptr if (flag == PACKED_FLAGS::UNPACKED) { uint32_t xdata_rva = details::xdata_unpacked_rva(*unwind_data); std::unique_ptr xdata_strm = ctx.stream_from_rva(xdata_rva); - return unwind_aarch64::UnpackedFunction::parse(ctx, *xdata_strm, xdata_rva, + return unwind_aarch64::UnpackedFunction::parse(ctx, *xdata_strm, size, + nb_scopes, xdata_rva, *rva_start); }