diff --git a/runtime/executor/method.cpp b/runtime/executor/method.cpp index 606b2460155..e45eff8c483 100644 --- a/runtime/executor/method.cpp +++ b/runtime/executor/method.cpp @@ -37,6 +37,20 @@ 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_assert( + (ET_MAX_INSTRUCTIONS) > 0, + "ET_MAX_INSTRUCTIONS must be positive. 0 would reject every program on " + "its first instruction; negative values wrap to SIZE_MAX when assigned " + "to size_t, silently disabling the infinite-loop guard."); +static constexpr size_t kMaxInstructions = ET_MAX_INSTRUCTIONS; + /** * Runtime state for a backend delegate. */ @@ -1661,6 +1675,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]; @@ -1674,6 +1689,21 @@ 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 at chain %" ET_PRIsize_t ", instruction %" ET_PRIsize_t + ". Possible infinite loop detected. If this is a legitimate " + "large model, raise the limit by rebuilding with " + "-DET_MAX_INSTRUCTIONS=.", + kMaxInstructions, + step_state_.chain_idx, + step_state_.instr_idx); + step_state_ = StepState{0, 0}; + return Error::InvalidProgram; + } + ++instruction_count; EXECUTORCH_PROFILE_INSTRUCTION_SCOPE( static_cast(step_state_.chain_idx), static_cast(step_state_.instr_idx));