Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix possible crash when scaling objects in editor #32158

Merged
merged 3 commits into from
Mar 4, 2025

Conversation

bdach
Copy link
Collaborator

@bdach bdach commented Feb 28, 2025

Fix possible crash when scaling objects in editor

Closes #32150.

The specific fail case here is when s.{X,Y} is 0, and s{Lower,Upper}Bound is Infinity. Because IEEE math is IEEE math, 0 * Infinity is NaN.

MathHelper.Clamp() is written the following way, using Math.{Min,Max}. Math.{Min,Max} are both documented as reporting NaN when any of their operands are NaN, which means that if a NaN happens to sneak into the bounds, it will start spreading outwards in an uncontrolled manner, and likely crash things.

In contrast, the standard library provided Math.Clamp() is written like so. With this implementation, if either bound is NaN, it will essentially not be checked (because any and all comparisons involving NaN return false). This prevents the spread of NaNs, all the way to positions of hitobjects, and thus fixes the crash.

Mark MathHelper.Clamp() as banned API

See above for partial rationale.

There's an argument to be made about the NaN-spreading semantics being desirable because at least something will loudly fail in that case, but I'm not so sure about that these days. It feels like either way if NaNs are produced, then things are outside of any control, and chances are the game can probably continue without crashing if the NaNs are not produced. And, this move reduces our dependence on osuTK, which has already been living on borrowed time for years now and is only awaiting someone brave to go excise it.

Verified

This commit was signed with the committer’s verified signature.
bdach Bartłomiej Dach
The specific fail case here is when `s.{X,Y}` is 0, and
`s{Lower,Upper}Bound` is `Infinity`. Because IEEE math is IEEE math,
`0 * Infinity` is `NaN`.

`MathHelper.Clamp()` is written the following way:

	https://github.com/ppy/osuTK/blob/af742f1afd01828efc7bc9fe77536b54aab8b419/src/osuTK/Math/MathHelper.cs#L284-L306

`Math.{Min,Max}` are both documented as reporting `NaN` when any of
their operands are `NaN`:

	https://learn.microsoft.com/en-us/dotnet/api/system.math.min?view=net-8.0#system-math-min(system-single-system-single)
	https://learn.microsoft.com/en-us/dotnet/api/system.math.max?view=net-8.0#system-math-max(system-single-system-single)

which means that if a `NaN` happens to sneak into the bounds, it will
start spreading outwards in an uncontrolled manner, and likely crash
things.

In contrast, the standard library provided `Math.Clamp()` is written
like so:

	https://github.com/dotnet/runtime/blob/577c36cee56480dec4d4610b35605b5d5836888b/src/libraries/System.Private.CoreLib/src/System/Math.cs#L711-L729

With this implementation, if either bound is `NaN`, it will essentially
not be checked (because any and all comparisons involving `NaN` return
false). This prevents the spread of `NaN`s, all the way to positions
of hitobjects, and thus fixes the crash.

Verified

This commit was signed with the committer’s verified signature.
bdach Bartłomiej Dach
See previous commit for partial rationale.

There's an argument to be made about the `NaN`-spreading semantics being
desirable because at least something will loudly fail in that case, but
I'm not so sure about that these days. It feels like either way if
`NaN`s are produced, then things are outside of any control, and chances
are the game can probably continue without crashing. And, this move
reduces our dependence on osuTK, which has already been living on
borrowed time for years now and is only awaiting someone brave to go
excise it.
peppy
peppy previously approved these changes Mar 1, 2025
Copy link
Member

@peppy peppy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds reasonable.

@peppy peppy requested a review from smoogipoo March 1, 2025 14:15
@bdach
Copy link
Collaborator Author

bdach commented Mar 2, 2025

Interesting test failures in https://github.com/ppy/osu/runs/37991745826#r1s0; blocking pending investigation.

(The fact that these failures are there now is another argument for ditching the osutk helper, as it would just silently do whatever if given invalid bounds.)

@bdach bdach added the blocked Don't merge this. label Mar 2, 2025

Verified

This commit was signed with the committer’s verified signature.
bdach Bartłomiej Dach
@bdach bdach removed the blocked Don't merge this. label Mar 3, 2025
@bdach
Copy link
Collaborator Author

bdach commented Mar 3, 2025

Tests should be fixed with 47747ae.

@peppy peppy merged commit 3fe92fb into ppy:master Mar 4, 2025
7 of 10 checks passed
@bdach bdach deleted the scaling-crash branch March 4, 2025 07:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Game crashes when moving 2> hitcircles really close together in the editor
2 participants