From c5e470b7afe5c32760af618b1816590fec0cf305 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 26 Apr 2012 19:56:11 +0200 Subject: [PATCH] Fixed thread-safety issue when accessing IProjectContent.ReferencedContents. Fixes InvalidOperationException in XamlCompilationUnit.FindType (crash #240) --- .../Project/Src/PythonResolverContext.cs | 4 +++- .../Project/Src/OptionPanels/ProjectImports.cs | 2 +- .../XamlBinding/CompletionDataHelper.cs | 2 +- .../XamlBinding/XamlBinding/XamlCompilationUnit.cs | 10 ++++++---- .../Project/Src/Services/TypeResolutionService.cs | 2 +- .../WpfDesign.AddIn/Src/IdeChooseClassService.cs | 2 +- .../WpfDesign/WpfDesign.AddIn/Src/MyTypeFinder.cs | 2 +- .../Project/Src/ContextActions/AddUsing.cs | 6 +++--- .../Src/MenuItemFactories/ResolveAttribute.cs | 4 ++-- .../MenuItemFactories/ResolveExtensionMethod.cs | 2 +- .../ParserService/AssemblyParserService.cs | 14 +++++++++----- src/Main/Base/Project/Src/Util/ExtensionMethods.cs | 7 +++++++ 12 files changed, 36 insertions(+), 21 deletions(-) diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonResolverContext.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonResolverContext.cs index c98cdfe6f3..c8f6129d3e 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonResolverContext.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonResolverContext.cs @@ -4,6 +4,8 @@ using System; using System.Collections; using System.Collections.Generic; + +using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Dom; namespace ICSharpCode.PythonBinding @@ -118,7 +120,7 @@ namespace ICSharpCode.PythonBinding public bool PartialNamespaceExistsInProjectReferences(string name) { - foreach (IProjectContent referencedContent in projectContent.ReferencedContents) { + foreach (IProjectContent referencedContent in projectContent.ThreadSafeGetReferencedContents()) { if (PartialNamespaceExists(referencedContent, name)) { return true; } diff --git a/src/AddIns/BackendBindings/VBNetBinding/Project/Src/OptionPanels/ProjectImports.cs b/src/AddIns/BackendBindings/VBNetBinding/Project/Src/OptionPanels/ProjectImports.cs index f189be0d58..766ef099d3 100644 --- a/src/AddIns/BackendBindings/VBNetBinding/Project/Src/OptionPanels/ProjectImports.cs +++ b/src/AddIns/BackendBindings/VBNetBinding/Project/Src/OptionPanels/ProjectImports.cs @@ -35,7 +35,7 @@ namespace ICSharpCode.VBNetBinding.OptionPanels } IProjectContent projectContent = ParserService.GetProjectContent(project); - foreach(IProjectContent refProjectContent in projectContent.ReferencedContents) { + foreach(IProjectContent refProjectContent in projectContent.ThreadSafeGetReferencedContents()) { AddNamespaces(refProjectContent); } diff --git a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/CompletionDataHelper.cs b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/CompletionDataHelper.cs index 6aec28a8c5..6ab91827e8 100644 --- a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/CompletionDataHelper.cs +++ b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/CompletionDataHelper.cs @@ -311,7 +311,7 @@ namespace ICSharpCode.XamlBinding { List list = new List(); - foreach (IProjectContent content in projectContent.ReferencedContents) { + foreach (IProjectContent content in projectContent.ThreadSafeGetReferencedContents()) { foreach (IAttribute att in content.GetAssemblyAttributes()) { if (att.PositionalArguments.Count == 2 && att.AttributeType.FullyQualifiedName == "System.Windows.Markup.XmlnsDefinitionAttribute") { diff --git a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlCompilationUnit.cs b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlCompilationUnit.cs index 7ac7da7d53..dbba1cbb8b 100644 --- a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlCompilationUnit.cs +++ b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlCompilationUnit.cs @@ -2,10 +2,12 @@ // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; -using System.Linq; -using ICSharpCode.SharpDevelop.Dom; using System.Collections; using System.Collections.Generic; +using System.Linq; + +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.Dom; namespace ICSharpCode.XamlBinding { @@ -81,7 +83,7 @@ namespace ICSharpCode.XamlBinding IReturnType type = FindTypeInAssembly(pc, xmlNamespace, className); if (type != null) return type; - foreach (IProjectContent p in pc.ReferencedContents) { + foreach (IProjectContent p in pc.ThreadSafeGetReferencedContents()) { type = FindTypeInAssembly(p, xmlNamespace, className); if (type != null) return type; @@ -117,7 +119,7 @@ namespace ICSharpCode.XamlBinding else { var list = new List(); AddNamespaceMembersInAssembly(pc, xmlNamespace, list); - foreach (IProjectContent p in pc.ReferencedContents) { + foreach (IProjectContent p in pc.ThreadSafeGetReferencedContents()) { AddNamespaceMembersInAssembly(p, xmlNamespace, list); } return list.OfType(); diff --git a/src/AddIns/DisplayBindings/FormsDesigner/Project/Src/Services/TypeResolutionService.cs b/src/AddIns/DisplayBindings/FormsDesigner/Project/Src/Services/TypeResolutionService.cs index 943c8c39aa..3b484f99e6 100644 --- a/src/AddIns/DisplayBindings/FormsDesigner/Project/Src/Services/TypeResolutionService.cs +++ b/src/AddIns/DisplayBindings/FormsDesigner/Project/Src/Services/TypeResolutionService.cs @@ -128,7 +128,7 @@ namespace ICSharpCode.FormsDesigner.Services try { // load dependencies of current assembly - foreach (IProjectContent rpc in pc.ReferencedContents) { + foreach (IProjectContent rpc in pc.ThreadSafeGetReferencedContents()) { if (rpc is ParseProjectContent) { LoadAssembly(rpc); } else if (rpc is ReflectionProjectContent) { diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.AddIn/Src/IdeChooseClassService.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.AddIn/Src/IdeChooseClassService.cs index 7714a4b85b..1c575877da 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.AddIn/Src/IdeChooseClassService.cs +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.AddIn/Src/IdeChooseClassService.cs @@ -43,7 +43,7 @@ namespace ICSharpCode.WpfDesign.AddIn var pc = ParserService.CurrentProjectContent; var a = GetAssembly(pc); if (a != null) yield return a; - foreach (var r in pc.ReferencedContents) { + foreach (var r in pc.ThreadSafeGetReferencedContents()) { a = GetAssembly(r); if (a != null) yield return a; } diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.AddIn/Src/MyTypeFinder.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.AddIn/Src/MyTypeFinder.cs index 507b8215d6..82a6b0f8a8 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.AddIn/Src/MyTypeFinder.cs +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.AddIn/Src/MyTypeFinder.cs @@ -52,7 +52,7 @@ namespace ICSharpCode.WpfDesign.AddIn Assembly FindAssemblyInProjectReferences(IProjectContent pc, string name) { - foreach (IProjectContent referencedProjectContent in pc.ReferencedContents) { + foreach (IProjectContent referencedProjectContent in pc.ThreadSafeGetReferencedContents()) { if (name == referencedProjectContent.AssemblyName) { return this.typeResolutionService.LoadAssembly(referencedProjectContent); } diff --git a/src/AddIns/Misc/SharpRefactoring/Project/Src/ContextActions/AddUsing.cs b/src/AddIns/Misc/SharpRefactoring/Project/Src/ContextActions/AddUsing.cs index 7c4a1dd317..b119c4b4f6 100644 --- a/src/AddIns/Misc/SharpRefactoring/Project/Src/ContextActions/AddUsing.cs +++ b/src/AddIns/Misc/SharpRefactoring/Project/Src/ContextActions/AddUsing.cs @@ -48,7 +48,7 @@ namespace SharpRefactoring.ContextActions IProjectContent pc = context.ProjectContent; SearchAllExtensionMethodsWithName(results, pc, rr.CallName); - foreach (IProjectContent content in pc.ReferencedContents) + foreach (IProjectContent content in pc.ThreadSafeGetReferencedContents()) SearchAllExtensionMethodsWithName(results, content, rr.CallName); foreach (IClass c in results) { @@ -99,7 +99,7 @@ namespace SharpRefactoring.ContextActions public string Search(UnknownMethodResolveResult rr, IProjectContent pc, List results) { SearchAttributesWithName(results, pc, rr.CallName); - foreach (IProjectContent content in pc.ReferencedContents) + foreach (IProjectContent content in pc.ThreadSafeGetReferencedContents()) SearchAttributesWithName(results, content, rr.CallName); return rr.CallName; } @@ -107,7 +107,7 @@ namespace SharpRefactoring.ContextActions public string Search(UnknownIdentifierResolveResult rr, IProjectContent pc, List results) { SearchAttributesWithName(results, pc, rr.Identifier); - foreach (IProjectContent content in pc.ReferencedContents) + foreach (IProjectContent content in pc.ThreadSafeGetReferencedContents()) SearchAttributesWithName(results, content, rr.Identifier); return rr.Identifier; } diff --git a/src/AddIns/Misc/SharpRefactoring/Project/Src/MenuItemFactories/ResolveAttribute.cs b/src/AddIns/Misc/SharpRefactoring/Project/Src/MenuItemFactories/ResolveAttribute.cs index 9c1e6aa7f3..2578f994b5 100644 --- a/src/AddIns/Misc/SharpRefactoring/Project/Src/MenuItemFactories/ResolveAttribute.cs +++ b/src/AddIns/Misc/SharpRefactoring/Project/Src/MenuItemFactories/ResolveAttribute.cs @@ -42,7 +42,7 @@ namespace SharpRefactoring var rr = context.ResolveResult as UnknownMethodResolveResult; SearchAttributesWithName(results, pc, rr.CallName); - foreach (IProjectContent content in pc.ReferencedContents) + foreach (IProjectContent content in pc.ThreadSafeGetReferencedContents()) SearchAttributesWithName(results, content, rr.CallName); name = rr.CallName; @@ -52,7 +52,7 @@ namespace SharpRefactoring var rr = context.ResolveResult as UnknownIdentifierResolveResult; SearchAttributesWithName(results, pc, rr.Identifier); - foreach (IProjectContent content in pc.ReferencedContents) + foreach (IProjectContent content in pc.ThreadSafeGetReferencedContents()) SearchAttributesWithName(results, content, rr.Identifier); name = rr.Identifier; diff --git a/src/AddIns/Misc/SharpRefactoring/Project/Src/MenuItemFactories/ResolveExtensionMethod.cs b/src/AddIns/Misc/SharpRefactoring/Project/Src/MenuItemFactories/ResolveExtensionMethod.cs index 24cdadfdf2..c37a3afe72 100644 --- a/src/AddIns/Misc/SharpRefactoring/Project/Src/MenuItemFactories/ResolveExtensionMethod.cs +++ b/src/AddIns/Misc/SharpRefactoring/Project/Src/MenuItemFactories/ResolveExtensionMethod.cs @@ -38,7 +38,7 @@ namespace SharpRefactoring SearchAllExtensionMethodsWithName(results, context.ProjectContent, rr.CallName); - foreach (IProjectContent content in context.ProjectContent.ReferencedContents) + foreach (IProjectContent content in context.ProjectContent.ThreadSafeGetReferencedContents()) SearchAllExtensionMethodsWithName(results, content, rr.CallName); if (!results.Any()) diff --git a/src/Main/Base/Project/Src/Services/ParserService/AssemblyParserService.cs b/src/Main/Base/Project/Src/Services/ParserService/AssemblyParserService.cs index 6fc81c2a40..8105154c1d 100644 --- a/src/Main/Base/Project/Src/Services/ParserService/AssemblyParserService.cs +++ b/src/Main/Base/Project/Src/Services/ParserService/AssemblyParserService.cs @@ -3,10 +3,12 @@ using System; using System.Collections.Generic; +using System.IO; +using System.Linq; + using ICSharpCode.Core; using ICSharpCode.SharpDevelop.Dom; using ICSharpCode.SharpDevelop.Project; -using System.IO; using RegistryContentPair = System.Collections.Generic.KeyValuePair; namespace ICSharpCode.SharpDevelop @@ -134,7 +136,7 @@ namespace ICSharpCode.SharpDevelop foreach (ProjectContentRegistryDescriptor registry in registries) { if (registry.IsRegistryLoaded) { foreach (IProjectContent pc in registry.Registry.GetLoadedProjectContents()) { - if (pc.ReferencedContents.Contains(referencedContent)) { + if (pc.ThreadSafeGetReferencedContents().Contains(referencedContent)) { if (unloadedReferenceContents.Add(pc)) { LoggingService.Debug("Mark dependent content for unloading " + pc); otherContentsToUnload.Add(new RegistryContentPair(registry.Registry, pc)); @@ -148,9 +150,11 @@ namespace ICSharpCode.SharpDevelop IProject project = (IProject)pc.Project; if (projectsToRefresh.Contains(project)) continue; - if (pc.ReferencedContents.Remove(referencedContent)) { - LoggingService.Debug("UnloadReferencedContent: Mark project for reparsing " + project.Name); - projectsToRefresh.Add(project); + lock (pc.ReferencedContents) { + if (pc.ReferencedContents.Remove(referencedContent)) { + LoggingService.Debug("UnloadReferencedContent: Mark project for reparsing " + project.Name); + projectsToRefresh.Add(project); + } } } diff --git a/src/Main/Base/Project/Src/Util/ExtensionMethods.cs b/src/Main/Base/Project/Src/Util/ExtensionMethods.cs index 3d7fde7cf1..690537f4c1 100644 --- a/src/Main/Base/Project/Src/Util/ExtensionMethods.cs +++ b/src/Main/Base/Project/Src/Util/ExtensionMethods.cs @@ -618,6 +618,13 @@ namespace ICSharpCode.SharpDevelop return new Location(region.EndColumn, region.EndLine); } + public static IEnumerable ThreadSafeGetReferencedContents(this IProjectContent pc) + { + lock (pc.ReferencedContents) { + return pc.ReferencedContents.ToList(); + } + } + public static int PositionToOffset(this IDocument document, Location location) { return document.PositionToOffset(location.Line, location.Column);