Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions runtime/executor/method.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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=<value>.
#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;
Comment thread
lucylq marked this conversation as resolved.

/**
* Runtime state for a backend delegate.
*/
Expand Down Expand Up @@ -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];
Expand All @@ -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=<value>.",
kMaxInstructions,
step_state_.chain_idx,
step_state_.instr_idx);
step_state_ = StepState{0, 0};
return Error::InvalidProgram;
}
Comment on lines +1692 to +1705
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This introduces a new failure mode in Method::execute() that should be covered by a regression test. Consider adding a unit test that builds a minimal flatbuffer program with a self-looping jump (or otherwise forces an infinite instruction loop) and asserts execute() fails once the instruction limit is exceeded (ideally with a small ET_MAX_INSTRUCTIONS value for the test target to keep runtime short).

Copilot uses AI. Check for mistakes.
++instruction_count;
EXECUTORCH_PROFILE_INSTRUCTION_SCOPE(
static_cast<int32_t>(step_state_.chain_idx),
static_cast<uint32_t>(step_state_.instr_idx));
Expand Down
Loading