Fix LoopLimit not enforced in nested loops defect #616
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Fixes a critical bug where
TemplateContext.LoopLimitwas not properly enforced in nested loop scenarios, allowing templates to bypass iteration limits and potentially cause performance issues or infinite loops.Problem
The original implementation used a single global
_loopStepcounter that was reset when entering/exiting any loop, causing nested loops to bypass theLoopLimitenforcement:Reproduction case:
With
LoopLimit = 200, this should throw an exception but didn't.Solution
Replaced the single global counter with a stack-based approach where each loop level maintains its own iteration counter:
Changes Made
Core Implementation (
src/Scriban/TemplateContext.cs)private int _loopStep;→private FastStack<int> _loopSteps;_loopSteps = new FastStack<int>(4);in constructor_loopStep = 0;→_loopSteps.Push(0);inEnterLoop()_loopStep = 0;→_loopSteps.Pop();inExitLoop()StepLoop()Test Coverage (
src/Scriban.Tests/TestRuntime.cs)TestNestedLoopLimit()- Tests 3×3 nested loops with limit of 5TestNestedLoopLimitInnerLoopExceeds()- Tests inner loop exceeding limitTestNestedLoopLimitWithinBounds()- Tests nested loops within limitsTestTripleNestedLoopLimit()- Tests triple nested loopsTestNestedLoopLimitIndependentCounters()- Tests independent counters per levelVerification
Before Fix:
After Fix:
Impact
Testing
All existing tests pass, plus new comprehensive test coverage for nested loop scenarios.
Breaking Changes
None. This is a bug fix that maintains full backward compatibility.
Fixes #615