1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-13 18:47:27 +08:00
osu-lazer/osu.Game/Screens/Play
Bartłomiej Dach 3c5e9ac9a9
Fix possible double score submission when auto-retrying via perfect mod
Closes https://github.com/ppy/osu/issues/26035.

`submitOnFailOrQuit()`, as the name suggests, can be called both when
the player has failed, or when the player screen is being exited from.
Notably, when perfect mod with auto-retry is active, the two happen
almost simultaneously.

This double call exposes a data race in `submitScore()` concerning the
handling of `scoreSubmissionSource`. The race could be experimentally
confirmed by applying the following patch:

diff --git a/osu.Game/Screens/Play/SubmittingPlayer.cs b/osu.Game/Screens/Play/SubmittingPlayer.cs
index 83adf1f960..76dd29bbdb 100644
--- a/osu.Game/Screens/Play/SubmittingPlayer.cs
+++ b/osu.Game/Screens/Play/SubmittingPlayer.cs
@@ -228,6 +228,7 @@ private Task submitScore(Score score)
                 return Task.CompletedTask;
             }

+            Logger.Log($"{nameof(scoreSubmissionSource)} is {(scoreSubmissionSource == null ? "null" : "not null")}");
             if (scoreSubmissionSource != null)
                 return scoreSubmissionSource.Task;

@@ -237,6 +238,7 @@ private Task submitScore(Score score)

             Logger.Log($"Beginning score submission (token:{token.Value})...");

+            Logger.Log($"creating new {nameof(scoreSubmissionSource)}");
             scoreSubmissionSource = new TaskCompletionSource<bool>();
             var request = CreateSubmissionRequest(score, token.Value);

which would result in the following log output:

	[runtime] 2024-01-02 09:54:13 [verbose]: scoreSubmissionSource is null
	[runtime] 2024-01-02 09:54:13 [verbose]: scoreSubmissionSource is null
	[runtime] 2024-01-02 09:54:13 [verbose]: Beginning score submission (token:36780)...
	[runtime] 2024-01-02 09:54:13 [verbose]: creating new scoreSubmissionSource
	[runtime] 2024-01-02 09:54:13 [verbose]: Beginning score submission (token:36780)...
	[runtime] 2024-01-02 09:54:13 [verbose]: creating new scoreSubmissionSource
	[network] 2024-01-02 09:54:13 [verbose]: Performing request osu.Game.Online.Solo.SubmitSoloScoreRequest
	[network] 2024-01-02 09:54:14 [verbose]: Request to https://dev.ppy.sh/api/v2/beatmaps/869310/solo/scores/36780 successfully completed!
	[network] 2024-01-02 09:54:14 [verbose]: SubmitSoloScoreRequest finished with response size of 639 bytes
	[network] 2024-01-02 09:54:14 [verbose]: Performing request osu.Game.Online.Solo.SubmitSoloScoreRequest
	[runtime] 2024-01-02 09:54:14 [verbose]: Score submission completed! (token:36780 id:20247)
	[network] 2024-01-02 09:54:14 [verbose]: Request to https://dev.ppy.sh/api/v2/beatmaps/869310/solo/scores/36780 successfully completed!
	[network] 2024-01-02 09:54:14 [verbose]: SubmitSoloScoreRequest finished with response size of 639 bytes
	[runtime] 2024-01-02 09:54:14 [error]: An unhandled error has occurred.
	[runtime] 2024-01-02 09:54:14 [error]: System.InvalidOperationException: An attempt was made to transition a task to a final state when it had already completed.
	[runtime] 2024-01-02 09:54:14 [error]: at osu.Game.Screens.Play.SubmittingPlayer.<>c__DisplayClass30_0.<submitScore>b__0(MultiplayerScore s) in /home/dachb/Documents/opensource/osu/osu.Game/Screens/Play/SubmittingPlayer.cs:line 250

The intention of the submission logic was to only ever create one
`scoreSubmissionSource`, and then reuse this one if a redundant
submission request was made. However, because of the temporal proximity
of fail and quit in this particular case, combined with the fact that
the calls to `submitScore()` are taking place on TPL threads, means that
there is a read-write data race on `scoreSubmissionSource`, wherein the
source can be actually created twice.

This leads to two concurrent score submission requests, which, upon
completion, attempt to transition only _the second_
`scoreSubmissionSource` to a final state (this is because the API
success/failure request callbacks capture `this`, i.e. the entire
`SubmittingPlayer` instance, rather than the `scoreSubmissionSource`
reference specifically).

To fix, ensure correct synchronisation on the read-write critical
section, which should prevent the `scoreSubmissionSource` from being
created multiple times.
2024-01-02 10:55:52 +01:00
..
Break Fix valueText being replaced even if current is not binding to anything 2023-08-02 09:40:22 -07:00
HUD Merge pull request #25673 from frenzibyte/fix-argon-initial-display 2023-12-13 22:16:34 +09:00
PlayerSettings Fix code quality inspection 2023-12-28 14:12:28 +01:00
ArgonKeyCounter.cs Use left aligned text for non-rotate key counter 2023-11-06 16:32:12 +09:00
ArgonKeyCounterDisplay.cs Refactor KeyCounterDisplay to use autosize 2023-11-12 17:19:25 +09:00
BeatmapMetadataDisplay.cs Refactor IWorkingBeatmap.Background to GetBackground() 2023-06-08 16:19:32 +09:00
BreakOverlay.cs Fix valueText being replaced even if current is not binding to anything 2023-08-02 09:40:22 -07:00
BreakTracker.cs Partial everything 2022-11-27 00:00:27 +09:00
ComboEffects.cs Replace various local implementations of rewinding checks with new property 2023-07-07 15:21:24 +09:00
DimmableStoryboard.cs Partial everything 2022-11-27 00:00:27 +09:00
EpilepsyWarning.cs Partial everything 2022-11-27 00:00:27 +09:00
FailAnimationContainer.cs Rename FailAnimation to FailAnimationContainer 2023-10-08 00:39:30 +09:00
FailOverlay.cs Don't show buttons on fail overlay when player interaction is disabled 2023-11-27 12:25:24 +09:00
GameplayClockContainer.cs Cache GameplayClockContainer to allow usage of OnSeek 2023-12-13 16:13:08 +09:00
GameplayClockExtensions.cs Rename GameplayAdjustments -> AdjustmentsFromMods 2022-09-08 17:14:06 +09:00
GameplayMenuOverlay.cs Fix using "Back" binding at spectator fail screen not working 2023-12-28 20:14:18 +09:00
GameplayOffsetControl.cs Disable positional interaction for now 2023-12-24 03:00:51 +09:00
GameplayState.cs Fix TestSceneReplayRecorder not using score provided by gameplay state 2022-07-25 05:21:27 +03:00
HotkeyExitOverlay.cs Automated pass 2023-06-24 01:00:03 +09:00
HotkeyRetryOverlay.cs Automated pass 2023-06-24 01:00:03 +09:00
HUDOverlay.cs Merge branch 'master' into leaderboard-toggle 2023-08-10 22:50:55 +02:00
IGameplayClock.cs Expose rewinding state of IGameplayClocks 2023-07-06 19:08:42 +09:00
ILocalUserPlayInfo.cs Automated pass 2023-06-24 01:00:03 +09:00
MasterGameplayClockContainer.cs Fix elapsed time being counted twice on first frame 2023-12-27 00:11:22 +09:00
OffsetCorrectionClock.cs Split OffsetCorrectionClock out of MasterGameplayClockContainer 2022-08-18 18:54:10 +09:00
PauseOverlay.cs Fix using "Back" binding at spectator fail screen not working 2023-12-28 20:14:18 +09:00
Player.cs Add control to allow changing offset from gameplay 2023-12-23 20:51:30 +09:00
PlayerConfiguration.cs Automated pass 2023-06-24 01:00:03 +09:00
PlayerLoader.cs Migrate BeatmapOffsetControl to use session static directly 2023-12-27 19:19:27 +01:00
PlayerTouchInputDetector.cs Fix PlayerTouchInputDetector applying touch device mod when other inactive mods present 2023-11-09 17:51:01 +09:00
ReplayPlayer.cs Allow autoplay to fail 2023-07-13 13:41:35 +09:00
ReplayPlayerLoader.cs Automated pass 2023-06-24 01:00:03 +09:00
ResumeOverlay.cs Partial everything 2022-11-27 00:00:27 +09:00
RoomSubmittingPlayer.cs Partial everything 2022-11-27 00:00:27 +09:00
SaveFailedScoreButton.cs Prevent ExportReplay being spammed on fail by being held down 2023-12-20 08:41:16 -08:00
ScreenSuspensionHandler.cs Partial everything 2022-11-27 00:00:27 +09:00
ScreenWithBeatmapBackground.cs Fix song select potentially updating background parameters when not the current screen 2023-02-16 18:45:22 +09:00
SkipOverlay.cs Fix various other inspections 2023-10-17 17:48:51 +09:00
SoloPlayer.cs Silence a few remaining nullability warnings 2023-07-04 22:39:26 +02:00
SoloSpectatorPlayer.cs Add visualisation of when a spectated player fails 2023-11-24 14:44:57 +09:00
SoloSpectatorScreen.cs Add extra test coverage and handle case where still at loading screen 2023-11-24 15:05:39 +09:00
SpectatorPlayer.cs Show back button when spectating 2023-12-15 11:26:17 +09:00
SpectatorPlayerLoader.cs Automated pass 2023-06-24 01:00:03 +09:00
SpectatorResultsScreen.cs Manual fixes to reduce warnings to zero 2023-06-24 01:52:53 +09:00
SquareGraph.cs Fix some new nullable inspections 2023-10-30 15:10:10 +09:00
SubmittingPlayer.cs Fix possible double score submission when auto-retrying via perfect mod 2024-01-02 10:55:52 +01:00