1
0
mirror of https://github.com/ppy/osu.git synced 2024-09-22 00:47:24 +08:00
osu-lazer/osu.Game
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
..
Audio Add inline note about deadlock 2023-12-26 12:06:56 +09:00
Beatmaps Change default values of new object counts to -1 to identify non-processed values 2023-12-19 18:20:02 +09:00
Collections Merge pull request #25821 from bdach/fix-collection-dropdown-crash 2023-12-19 01:01:23 +09:00
Configuration Fix global audio offset suggestion feature not taking previous offset value into account 2023-12-29 12:20:58 +01:00
Database Fix standardised score conversion failing for scores set with 0.0x mod mutliplier 2023-12-23 13:28:39 +01:00
Extensions Merge branch 'master' into score-encoding-cleanup 2023-10-26 09:04:05 +02:00
Graphics Update dropdown disabled state to match with other components 2023-12-29 05:31:13 +03:00
Input Add basic hotkey offset adjust support (via existing offset control) 2023-12-23 19:55:05 +09:00
IO Fix various other inspections 2023-10-17 17:48:51 +09:00
IPC Handle osu:// scheme links via IPC in desktop game 2022-06-20 21:26:22 +02:00
Localisation Merge pull request #26184 from peppy/spectate-from-context-menu 2023-12-28 12:24:29 +01:00
Models Remove usages of [ExcludeFromDynamicCompile] 2023-05-08 18:12:56 +09:00
Online Add very simple cache-busting (30 minutes) 2023-12-28 14:40:10 +09:00
Overlays Merge pull request #26267 from frenzibyte/fix-audio-offset-adjust-control 2023-12-31 16:32:13 +09:00
Performance Automated pass 2023-06-24 01:00:03 +09:00
Properties Automated pass 2023-06-24 01:00:03 +09:00
Replays Show smoke in replays 2022-09-18 17:55:06 -07:00
Rulesets Expose Mod.UsesDefaultConfiguration 2023-12-29 17:16:16 +09:00
Scoring Store last set score to a SessionStatic 2023-12-27 19:13:42 +01:00
Screens Fix possible double score submission when auto-retrying via perfect mod 2024-01-02 10:55:52 +01:00
Skinning Make mania scroll speed independent of hit position 2023-12-26 12:46:21 +09:00
Storyboards Minor reword on documentation 2023-10-28 03:18:13 +03:00
Tests Add mania/osu sudden death mod tests 2023-12-22 16:43:09 +09:00
Updater use fa_download for updates instead of fa_upload 2023-07-16 15:21:15 -04:00
Users Add the ability to spectate a user by right clicking their user panel 2023-12-28 17:35:10 +09:00
Utils Automatically activate and deactivate touch device mod in song select 2023-11-02 19:45:48 +01:00
.editorconfig
BackgroundDataStoreProcessor.cs Add accuracy conversion, fix usages 2023-12-21 15:09:56 +09:00
FodyWeavers.xml More realm analytic disables 2023-07-20 17:51:33 +09:00
osu!.res
osu.Game.csproj Update resources 2023-12-28 03:04:13 +09:00
OsuGame.cs Do not show main menu version display on deployed builds 2023-12-29 11:14:28 +01:00
OsuGameBase_Importing.cs Automated pass 2023-06-24 01:00:03 +09:00
OsuGameBase.cs Remove unused using 2023-12-28 14:30:11 +01:00
PerformFromMenuRunner.cs Partial everything 2022-11-27 00:00:27 +09:00