Skip to content

Fix #633: [Bug] Stack-overflow due to infinite recursion in user-defined operator (string interpolation)#700

Merged
lefticus merged 4 commits into
ChaiScript:developfrom
leftibot:fix/issue-633-bug-stack-overflow-due-to-infinite-recur
May 2, 2026
Merged

Fix #633: [Bug] Stack-overflow due to infinite recursion in user-defined operator (string interpolation)#700
lefticus merged 4 commits into
ChaiScript:developfrom
leftibot:fix/issue-633-bug-stack-overflow-due-to-infinite-recur

Conversation

@leftibot

Copy link
Copy Markdown
Contributor

Automated fix by @leftibot.

What changed

Fix #633: Bound ChaiScript call stack to prevent native stack overflow
Recursive user-defined operators (e.g. a string::/= whose body calls
itself through string interpolation) drove the AST evaluator into
unbounded native recursion and crashed the host process with SIGSEGV.
The dispatcher now refuses to enter a new function frame once
Stack_Holder::call_depth reaches chaiscript::max_call_depth
(default 256, overridable via the CHAISCRIPT_MAX_CALL_DEPTH macro)
and throws the new chaiscript::exception::stack_overflow_error
instead, letting both ChaiScript-level try/catch and C++ hosts
recover from runaway recursion.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com

Files

 include/chaiscript/chaiscript_defines.hpp      | 11 ++++++++
 include/chaiscript/dispatchkit/dispatchkit.hpp | 17 +++++++++++
 unittests/recursion_depth_protection.chai      | 39 ++++++++++++++++++++++++++
 3 files changed, 67 insertions(+)

Closes #633

Triggered by @lefticus.

…ck overflow

Recursive user-defined operators (e.g. a `string::/=` whose body calls
itself through string interpolation) drove the AST evaluator into
unbounded native recursion and crashed the host process with SIGSEGV.
The dispatcher now refuses to enter a new function frame once
`Stack_Holder::call_depth` reaches `chaiscript::max_call_depth`
(default 256, overridable via the `CHAISCRIPT_MAX_CALL_DEPTH` macro)
and throws the new `chaiscript::exception::stack_overflow_error`
instead, letting both ChaiScript-level `try`/`catch` and C++ hosts
recover from runaway recursion.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@lefticus

Copy link
Copy Markdown
Member

@leftibot you have a failure on Windows, investigate.

Windows MSVC Debug builds crashed unit.recursion_depth_protection.chai
with SEGFAULT before the depth check could fire. Windows defaults to a
1 MiB thread stack and Debug builds emit much larger per-frame native
stack usage (no inlining, /RTC, buffer security checks), so 256 nested
ChaiScript calls overflow the native stack long before the dispatcher
reaches max_call_depth. Linux/macOS and MSVC Release pass at 256.

Pick a tighter default (32) only for the MSVC + _DEBUG configuration
that needs it, leaving every other build at the original 256, and shrink
the count_down recursion in the regression test so the bounded path
stays well below every platform's default.

Requested by @lefticus in PR ChaiScript#700 review.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@leftibot

Copy link
Copy Markdown
Contributor Author

Addressed review feedback from @lefticus. New commits:

ec05fcf3 Address review: tighten max_call_depth on MSVC Debug

@lefticus lefticus left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Use the CHAISCRIPT_DEBUG and other appropriately defined macros instead of checking for _ndebug @leftibot

Switch CHAISCRIPT_DEBUG from a true/false definition to 1/0 so it can
be used in preprocessor #if expressions, then reuse it for the MSVC
Debug guard around CHAISCRIPT_MAX_CALL_DEPTH instead of testing the
compiler-private _DEBUG macro directly. The C++ debug_build constant
keeps its bool value through implicit conversion.

Requested by @lefticus in PR ChaiScript#700 review.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@leftibot

leftibot commented May 2, 2026

Copy link
Copy Markdown
Contributor Author

Addressed review feedback from @lefticus. New commits:

bd6fd1f2 Address review: use CHAISCRIPT_DEBUG instead of _DEBUG

@lefticus lefticus left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@leftibot why did you change the type from true to 1 for the macro? We want stronger typing, not truthy

…yping

C++ preserves the true/false keywords in #if directives ([cpp.cond]),
so the MSVC Debug guard around CHAISCRIPT_MAX_CALL_DEPTH still works
without weakening the macro to integer 1/0.

Requested by @lefticus in PR ChaiScript#700 review.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@leftibot

leftibot commented May 2, 2026

Copy link
Copy Markdown
Contributor Author

Addressed review feedback from @lefticus. New commits:

1d354e11 Address review: restore CHAISCRIPT_DEBUG to true/false for stronger typing

@lefticus lefticus merged commit 85b8e7c into ChaiScript:develop May 2, 2026
21 of 22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Stack-overflow due to infinite recursion in user-defined operator (string interpolation)

2 participants