From 903067df9824f4c3712207593faa929803821388 Mon Sep 17 00:00:00 2001 From: Github Executorch Date: Wed, 4 Mar 2026 22:33:18 -0800 Subject: [PATCH] Add instruction execution limit to prevent infinite loops (TOB-EXECUTORCH-23) JumpFalseCall instructions can set destination_instruction to themselves, creating an infinite loop that hangs the runtime. This adds a configurable instruction counter (default 10M, overridable via -DET_MAX_INSTRUCTIONS) to Method::execute() that returns Error::InvalidState if exceeded. This PR was authored with the assistance of Claude. --- runtime/executor/method.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/runtime/executor/method.cpp b/runtime/executor/method.cpp index 165caa63549..028f830f173 100644 --- a/runtime/executor/method.cpp +++ b/runtime/executor/method.cpp @@ -37,6 +37,15 @@ namespace ET_RUNTIME_NAMESPACE { using internal::PlatformMemoryAllocator; +// Maximum number of instructions that Method::execute() will run before +// returning an error. Prevents infinite loops caused by malformed programs +// (e.g., JumpFalseCall instructions whose destination_instruction points to +// themselves). Override at compile time via -DET_MAX_INSTRUCTIONS=. +#ifndef ET_MAX_INSTRUCTIONS +#define ET_MAX_INSTRUCTIONS 10000000 +#endif +static constexpr size_t kMaxInstructions = ET_MAX_INSTRUCTIONS; + /** * Runtime state for a backend delegate. */ @@ -1644,6 +1653,7 @@ Error Method::execute() { // Chains are executed sequentially today, but future async designs may // branch and run many in parallel or out of order. + size_t instruction_count = 0; for (step_state_.chain_idx = 0; step_state_.chain_idx < n_chains_; ++step_state_.chain_idx) { Chain& chain = chains_[step_state_.chain_idx]; @@ -1657,6 +1667,18 @@ Error Method::execute() { // Loop over instructions step_state_.instr_idx = 0; while (step_state_.instr_idx < chain.s_chain_->instructions()->size()) { + if (instruction_count >= kMaxInstructions) { + ET_LOG( + Error, + "Instruction execution limit (%" ET_PRIsize_t + ") exceeded in chain %" ET_PRIsize_t + ". Possible infinite loop detected.", + kMaxInstructions, + step_state_.chain_idx); + step_state_ = StepState{0, 0}; + return Error::InvalidState; + } + ++instruction_count; EXECUTORCH_PROFILE_INSTRUCTION_SCOPE( static_cast(step_state_.chain_idx), static_cast(step_state_.instr_idx));