ui: a runaway frame writes its own line, and stops costing the whole bound twice
Two of his sessions froze this morning with nothing in the log. The journal says what happened: every frame 15,0xx ms, `main_ms` 14,970 of it, GPU 3 ms, the main thread `state R` with 64 s of CPU in 68 s of wall. That dead-constant 15.02 s is `RUNAWAY_FRAME_SECS` — a Lua loop that never returns, re-entered the next frame and the next. The bound did its job and said nothing, because its raise unwinds to whatever `pcall` caught the call. On this corpus that is always an addon's own guard, so the trip became nobody's script error: `session errors: 0`, no log line, no file, no line number. `WOW_UI_RAISES` would have caught it and is `eprintln!` only, which is no use to someone who is in the game. So the hook writes its own report before raising, and the host logs it at `error!` beside the ordinary error drain. Each kept report carries a sixteen frame traceback, because the innermost line is usually inside a library and the handler that entered the loop is the name worth having. And the bound tightens to a second once it has tripped. The first one has to be far beyond any legitimate frame, which makes it far beyond playable: a loop is re-entered every frame, so the player gets one frame every fifteen seconds — indistinguishable from the freeze the bound exists to prevent, and that is exactly what he got. One trip has already proved the call non-terminating; the ones after it need only enough rope to say so. A second is still some 125M VM instructions, two orders past the heaviest handler ever measured here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgstFWtn1RxEJ5kVrpgYwn
This commit is contained in:
@@ -567,6 +567,13 @@ pub(super) fn tick_script(
|
||||
for err in script.take_errors() {
|
||||
warn!("ui_script: {err}");
|
||||
}
|
||||
// The runaway bound writes its own line, because its raise unwinds into whatever `pcall` the
|
||||
// loop was called under and usually becomes nobody's error. Without this a frame stuck in Lua
|
||||
// costs the bound's whole 15 s, every frame, and leaves the log silent — which is exactly what
|
||||
// two frozen sessions handed back.
|
||||
for r in script.take_runaway_reports() {
|
||||
error!("ui_script: {r}");
|
||||
}
|
||||
for w in script.take_warnings() {
|
||||
warn!("ui_script: {w}");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user