Skip to content

Commit 171eb2d

Browse files
committed
Data race on _allLoadedPlugins (List) across threads
1 parent 76cc22d commit 171eb2d

File tree

1 file changed

+18
-6
lines changed

1 file changed

+18
-6
lines changed

Flow.Launcher.Core/Plugin/PluginManager.cs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public static class PluginManager
2525
{
2626
private static readonly string ClassName = nameof(PluginManager);
2727

28-
private static List<PluginPair> _allLoadedPlugins;
28+
private static readonly ConcurrentDictionary<string, PluginPair> _allLoadedPlugins = [];
2929
private static readonly ConcurrentDictionary<string, PluginPair> _allInitializedPlugins = [];
3030
private static readonly ConcurrentDictionary<string, PluginPair> _initFailedPlugins = [];
3131
private static readonly ConcurrentDictionary<string, PluginPair> _globalPlugins = [];
@@ -204,7 +204,17 @@ public static void LoadPlugins(PluginsSettings settings)
204204
Settings.UpdatePluginSettings(metadatas);
205205

206206
// Load plugins
207-
_allLoadedPlugins = PluginsLoader.Plugins(metadatas, Settings);
207+
var allLoadedPlugins = PluginsLoader.Plugins(metadatas, Settings);
208+
foreach (var plugin in allLoadedPlugins)
209+
{
210+
if (plugin != null)
211+
{
212+
if (!_allLoadedPlugins.TryAdd(plugin.Metadata.ID, plugin))
213+
{
214+
PublicApi.Instance.LogError(ClassName, $"Plugin with ID {plugin.Metadata.ID} already loaded");
215+
}
216+
}
217+
}
208218

209219
// Since dotnet plugins need to get assembly name first, we should update plugin directory after loading plugins
210220
UpdatePluginDirectory(metadatas);
@@ -244,8 +254,10 @@ private static void UpdatePluginDirectory(List<PluginMetadata> metadatas)
244254
/// <returns>return the list of failed to init plugins or null for none</returns>
245255
public static async Task InitializePluginsAsync(IResultUpdateRegister register)
246256
{
247-
var initTasks = _allLoadedPlugins.Select(pair => Task.Run(async () =>
257+
var initTasks = _allLoadedPlugins.Select(x => Task.Run(async () =>
248258
{
259+
var pair = x.Value;
260+
249261
// Register plugin action keywords so that plugins can be queried in results
250262
RegisterPluginActionKeywords(pair);
251263

@@ -543,7 +555,7 @@ private static bool IsPluginInitializing(PluginMetadata metadata)
543555

544556
public static List<PluginPair> GetAllLoadedPlugins()
545557
{
546-
return [.. _allLoadedPlugins];
558+
return [.. _allLoadedPlugins.Values];
547559
}
548560

549561
public static List<PluginPair> GetAllInitializedPlugins(bool includeFailed)
@@ -655,7 +667,7 @@ public static bool IsHomePlugin(string id)
655667
public static bool IsInitializingOrInitFailed(string id)
656668
{
657669
// Id does not exist in loaded plugins
658-
if (!_allLoadedPlugins.Any(x => x.Metadata.ID == id)) return false;
670+
if (!_allLoadedPlugins.Any(x => x.Value.Metadata.ID == id)) return false;
659671

660672
// Plugin initialized already
661673
if (_allInitializedPlugins.ContainsKey(id))
@@ -962,7 +974,7 @@ internal static async Task<bool> UninstallPluginAsync(PluginMetadata plugin, boo
962974
}
963975
Settings.RemovePluginSettings(plugin.ID);
964976
{
965-
_allLoadedPlugins.RemoveAll(p => p.Metadata.ID == plugin.ID);
977+
_allLoadedPlugins.TryRemove(plugin.ID, out var _);
966978
}
967979
{
968980
_allInitializedPlugins.TryRemove(plugin.ID, out var _);

0 commit comments

Comments
 (0)