ChaiScript/unittests/recursion_depth_protection.chai
leftibot ec05fcf3d4 Address review: tighten max_call_depth on MSVC Debug
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 #700 review.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 16:54:56 -06:00

42 lines
1.2 KiB
ChaiScript

// Regression test for issue #633: Stack-overflow due to infinite recursion
// in user-defined operator (string interpolation).
//
// Before the fix the recursive `/=` invocation triggered unbounded native
// recursion in the evaluator and crashed the host process with a SIGSEGV.
// The engine now bounds call_depth and throws a catchable exception
// instead of letting the native stack overflow.
def string::`/=`(double d) {
this = "${this/= 2}/=${d}";
return this;
}
var s = "o World"
var caught = false
var message = ""
try {
s /= 2
// unreachable: the recursive operator must abort with an exception
assert_true(false)
} catch (e) {
caught = true
message = e.what()
}
assert_true(caught)
// The reported error must mention the call-stack overflow so users can
// distinguish it from an arbitrary script-level error.
assert_true(find(message, "call stack") != -1)
// A bounded recursion that stays well below the limit must keep working.
// Use a small depth so the test passes on every platform default - notably
// the MSVC Debug build where the native stack budget forces a tighter cap.
def count_down(n) {
if (n <= 0) { return 0 }
return count_down(n - 1) + 1
}
assert_equal(10, count_down(10))