Fix storyboard decode hanging on self-referential variable definitions - #38505
Merged
peppy merged 3 commits intoAug 3, 2026
Merged
Conversation
A [Variables] entry whose value re-introduces its own key (e.g. $a=x$a) makes decodeVariables() re-scan and grow the line on every pass, so it never stops containing '$' and the loop never terminates. Decoding such a storyboard hangs the game with no way to recover other than force-killing the process. Substitute each defined variable a single time instead of looping until the line stabilises: storyboard variables are plain text substitutions not expected to reference other variables, so a single pass resolves every well-formed reference. Adds a regression test covering a self-referential definition.
Collaborator
|
Did you use "AI" tools when making this PR? |
Contributor
Author
I used translation tool to help me draft this PR. |
bdach
self-requested a review
August 3, 2026 11:31
peppy
approved these changes
Aug 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
A storyboard
[Variables]entry whose value re-introduces its own key causesLegacyStoryboardDecoder.decodeVariables()to loop forever, hanging the game.Details
decodeVariables()substitutes every variable into a line, repeating until a full pass makes no change:If a variable's value contains its own key (e.g.
$a=x$a), each pass replaces$awithx$a, so the line grows by one character every iteration, always still contains$, and never equalsorigLine— the loop never terminates. (A doubling form such as$a=$a$ainstead grows the line exponentially until it throwsOutOfMemoryException.)The storyboard is decoded lazily when a beatmap is played, so a beatmap containing such a storyboard imports normally and then hangs the client the moment the map is started. The
try/catchinWorkingBeatmapCache.GetStoryboard()cannot catch a non-terminating loop and there is no watchdog, so recovery requires force-killing the process.Minimal reproducer (as a
.osb, or the[Variables]/[Events]sections of a.osu):Fix
Substitute each defined variable a single time instead of repeatedly re-scanning the line. Storyboard variables are plain text substitutions and are not expected to reference other variables, so a single pass resolves every well-formed reference (including the existing
variable-with-suffixcase) while removing the re-scan that never terminates for a self-referential definition.Added a regression test that decodes a self-referential definition and asserts the surrounding well-formed sprite still decodes correctly.