1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-16 00:37:26 +08:00
osu-lazer/osu.Game.Rulesets.Osu
Bartłomiej Dach 89509ea49e
Fix DrawableOsuHitObject not properly cleaning up dim application callbacks
Should fix https://github.com/ppy/osu/issues/28629.

First of all, to support the claim that this does fix the issue -
reproduction is rather difficult, but I believe I found a way to
maximise the chances of it reproducing by performing the following
steps:

1. Apply the following diff:

diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs
index eacd2b3e75..4c00da031a 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs
@@ -6,6 +6,7 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using System.Threading;
 using JetBrains.Annotations;
 using osu.Framework.Allocation;
 using osu.Framework.Bindables;
@@ -95,6 +96,8 @@ public DrawableSlider([CanBeNull] Slider s = null)
         [BackgroundDependencyLoader]
         private void load()
         {
+            Thread.Sleep(100);
+
             tailContainer = new Container<DrawableSliderTail> { RelativeSizeAxes = Axes.Both };

             AddRangeInternal(new Drawable[]

2. Download https://osu.ppy.sh/beatmapsets/1470790#osu/3023028 and open
   it in the editor.

3. Select all objects using Ctrl-A. Yes, it'll take a while, especially
   so with the patch above.

4. Rotate the selection by any amount using the right toolbox.

5. Press undo. The game should crash. If it doesn't spam redo and undo
   until it does.

Now to explain what the fix is.

In the issue thread I spent a considerable time hemming and hawing about
which of the dimmable pieces was null, which was a complete miss and a
failure at reading. Let's see the stack trace again:

	2024-06-27 02:15:20 [error]: at osu.Game.Rulesets.Osu.Objects.Drawables.DrawableOsuHitObject.<UpdateInitialTransforms>g__applyDim|15_0(Drawable piece) in /home/runner/work/osu-auth-client/osu-auth-client/osu/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs:line 101

Line 101, you say? What could be null here?

	bd8addfb5f/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs (L101)

Okay, what's `InitialLifetimeOffset`, then?

	bd8addfb5f/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs (L108)

Yes, that's right. It's `HitObject` that is null here.

Now why does *that* happen? First, let's note that all stacks where this
died went through `UpdateState()`, which means that the problematic
`applyDim()` calls had to be `ApplyCustomUpdateState` event callbacks.
Meaning that the pieces where `HitObject` was null were DHOs themselves.

Recall that parent DHOs and child DHOs are pooled separately. Therefore,
there is no guarantee that any parent and child DHOs will remain
associated with each other for the entire duration of a gameplay
session; it is quite the contrary, and nobody should rely on that.
Unfortunately for us, adding a `applyDimToDrawableHitObject` callback to
a child object's `ApplyCustomUpdateState` *implicitly creates* such an
association, because it ends up allocating a closure that captures
`this` (meaning the parent in this context).

Therefore, this now creates a situation where a child DHO can attempt to
read state from a former parent DHO which can be in an indeterminate
state, and in fact, when this crashes, the former parent DHO is most
likely not even in use - hence the null `HitObject`.

Thus, the fix is to clear the association by unsubscribing from the
event when nested objects are cleared.

My hypothesis why the reproduction scenario is like it is, is that both
the sleep and the increased pressure on the pool (by way of selecting
all objects and therefore forcing the DHOs to be materialised beyond
pool capacity) increases the likelihood of getting a crosslink.
When pool pressure is low, it is much more likely that a parent DHO
*will* get the same child DHO again on re-application, even though
that is not guaranteed.

Just as an additional detail, note that the sentry issue for this lists
the "first seen" version as 2024.312.0, which is the release that
included https://github.com/ppy/osu/pull/27401 which would be directly
responsible for this mess.
2024-09-19 14:30:02 +02:00
..
Beatmaps Limit per-frame movement hitobject processing to stacking updates 2024-07-11 13:36:14 +02:00
Configuration Fix display length not resetting to default because default was wrong 2024-09-07 13:54:12 +09:00
Difficulty Merge branch 'master' into pp_refactoring_osustrainskill 2024-09-12 17:28:24 +09:00
Edit Merge branch 'master' into grids-3 2024-09-19 18:21:05 +09:00
Judgements Store tracking history to slider judgement result instead 2024-02-29 12:11:50 +01:00
Mods Support increased visibility for first object with traceable mod 2024-06-27 16:00:22 +09:00
Objects Fix DrawableOsuHitObject not properly cleaning up dim application callbacks 2024-09-19 14:30:02 +02:00
Properties Automated pass 2023-06-24 01:00:03 +09:00
Replays Update usage of MathUtils 2024-03-06 12:13:12 +08:00
Scoring Make RankFromScore()'s dictionary param readonly 2024-01-22 19:56:30 +01:00
Skinning Split out classes and avoid weird configuration stuff 2024-09-05 12:08:48 +09:00
Statistics Merge branch 'master' into heatmap-misses 2024-03-18 14:43:24 +01:00
UI Fix replay analysis overlay being affected by visibility impairing mods 2024-09-11 15:55:02 +02:00
Utils Automated pass 2023-06-24 01:00:03 +09:00
osu.Game.Rulesets.Osu.csproj Remove LangVersion redefintions 2024-02-07 03:28:40 +09:00
OsuInputManager.cs Fix taps on judged circles changing cursor position 2024-05-14 01:23:55 +09:00
OsuRuleset.cs fix config mistake 2024-09-04 03:37:52 -04:00
OsuSkinComponentLookup.cs Rename GameplaySkinComponentLookup -> SkinComponentLookup 2024-08-22 18:46:03 +09:00
OsuSkinComponents.cs remove skinnable 2024-02-27 21:51:54 -05:00