Skip to content

Fix --profile function timing stack leak on nextfile inside a function - #581

Merged
bertysentry merged 1 commit into
mainfrom
557-profile-function-timing-stack-leaks-on-nextnextfile-inside-a-function
Aug 18, 2026
Merged

Fix --profile function timing stack leak on nextfile inside a function#581
bertysentry merged 1 commit into
mainfrom
557-profile-function-timing-stack-leaks-on-nextnextfile-inside-a-function

Conversation

@bertysentry

Copy link
Copy Markdown
Contributor

Fixes #557

Problem

Under --profile, executeNextfile unwound the runtime call frames (popAllFrames + clearOperandStack) without touching activeProfilingFunctions. Every nextfile executed from inside a user-defined function therefore:

  • permanently leaked a deque entry (unbounded memory growth on long profiled runs), and
  • skewed the function timing report: the abandoned calls were missing from the report entirely when the program ended normally, or were "exited" at program exit with wildly wrong durations.

Fix

  • resetCallState() now records exits for all active profiling functions (via the existing recordAllFunctionExits) before unwinding, mirroring what EXIT_* does, so the durations end at the point the calls are abandoned.
  • executeNextfile delegates to resetCallState() instead of its inline two-line unwind. This also fixes a second leak on the same path: elementArgumentReferences was never cleared on nextfile.
  • The exception abort paths, which already went through resetCallState(), now settle the profiling stack the same way, so a reused AVM cannot carry stale entries into a later run.

Notes

  • The issue also names next inside a function, but Jawk currently rejects that at compile time (cannot next; not within any input rules) while gawk accepts it — that compat gap is tracked separately in next inside a user-defined function is rejected at compile time #580, and its future implementation will inherit this fix by unwinding through resetCallState().
  • New test profileOptionRecordsFunctionsUnwoundByNextfile drives --profile with a nested outer() -> inner() -> nextfile chain across three input files and asserts each function is reported with exactly 3 executions. It fails on unfixed code (inner/outer missing from the report) and passes with the fix.
  • User-visible profiling report change recorded under Unreleased in behavior-changes.md.

mvn verify passes (checkstyle, PMD, SpotBugs clean); the failsafe compat-suite failures are the known pre-existing ones (@load etc.), unrelated to this change.

🤖 Generated with Claude Code

Under --profile, executeNextfile unwound the runtime call frames without
touching activeProfilingFunctions, so every nextfile executed from inside
a user-defined function permanently leaked a deque entry (unbounded
growth on long profiled runs) and the abandoned calls were missing from
the function timing report, or accounted at program exit with wildly
wrong durations.

resetCallState() now records exits for all active profiling functions
before unwinding, and executeNextfile delegates to it instead of its
inline two-line unwind. This also fixes a second leak on the same path:
elementArgumentReferences was never cleared on nextfile. The exception
abort paths, which already went through resetCallState(), settle the
profiling stack the same way.

`next` inside a user-defined function, also named by the issue, is
currently rejected at compile time (gawk accepts it); that compat gap is
tracked separately in #580.

Fixes #557

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@bertysentry
bertysentry merged commit d64f1f9 into main Aug 18, 2026
5 checks passed
@bertysentry
bertysentry deleted the 557-profile-function-timing-stack-leaks-on-nextnextfile-inside-a-function branch August 18, 2026 18:56
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.

--profile: function timing stack leaks on next/nextfile inside a function

1 participant