diff --git a/explorer/interpreter/action_stack.h b/explorer/interpreter/action_stack.h index 383dd8562cc6..4f4b686f9e44 100644 --- a/explorer/interpreter/action_stack.h +++ b/explorer/interpreter/action_stack.h @@ -119,6 +119,8 @@ class ActionStack { void Pop() { todo_.Pop(); } + auto Count() const -> int { return todo_.Count(); } + private: // Pop any ScopeActions from the top of the stack, propagating results as // needed, to restore the invariant that todo_.Top() is not a ScopeAction. diff --git a/explorer/interpreter/interpreter.cpp b/explorer/interpreter/interpreter.cpp index a17ed744a185..e143c259f22b 100644 --- a/explorer/interpreter/interpreter.cpp +++ b/explorer/interpreter/interpreter.cpp @@ -952,6 +952,10 @@ auto Interpreter::CallFunction(const CallExpression& call, Nonnull fun, Nonnull arg, ImplWitnessMap&& witnesses) -> ErrorOr { + constexpr int StackSizeLimit = 1000; + if (todo_.Count() > StackSizeLimit) { + return ProgramError(call.source_loc()) << "stack overflow"; + } if (trace_stream_->is_enabled()) { *trace_stream_ << "calling function: " << *fun << "\n"; } diff --git a/explorer/testdata/function/fail_recursion_stackoverflow.carbon b/explorer/testdata/function/fail_recursion_stackoverflow.carbon new file mode 100644 index 000000000000..153b9718b8a3 --- /dev/null +++ b/explorer/testdata/function/fail_recursion_stackoverflow.carbon @@ -0,0 +1,20 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE +// RUN: %{not} %{explorer-run} +// RUN: %{not} %{explorer-run-trace} + +package EmptyIdentifier impl; + +fn A() { + // CHECK:STDERR: RUNTIME ERROR: {{.*}}/explorer/testdata/function/fail_recursion_stackoverflow.carbon:[[@LINE+1]]: stack overflow + A(); +} + +fn Main() -> i32 +{ + A(); + return 0; +}