diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ResourceInclude.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ResourceInclude.cs index 87e2ba3a2e..0cedf4f364 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ResourceInclude.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ResourceInclude.cs @@ -13,6 +13,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions { private Uri? _baseUri; private IResourceDictionary? _loaded; + private bool _isLoading; /// /// Gets the loaded resource dictionary. @@ -23,8 +24,10 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions { if (_loaded == null) { + _isLoading = true; var loader = new AvaloniaXamlLoader(); _loaded = (IResourceDictionary)loader.Load(Source, _baseUri); + _isLoading = false; } return _loaded; @@ -48,7 +51,13 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions bool IResourceNode.TryGetResource(object key, out object? value) { - return Loaded.TryGetResource(key, out value); + if (!_isLoading) + { + return Loaded.TryGetResource(key, out value); + } + + value = null; + return false; } void IResourceProvider.AddOwner(IResourceHost owner) => Loaded.AddOwner(owner); diff --git a/src/Markup/Avalonia.Markup.Xaml/Styling/StyleInclude.cs b/src/Markup/Avalonia.Markup.Xaml/Styling/StyleInclude.cs index 2b39263ee9..ea9042f779 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Styling/StyleInclude.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Styling/StyleInclude.cs @@ -14,6 +14,7 @@ namespace Avalonia.Markup.Xaml.Styling { private readonly Uri _baseUri; private IStyle[]? _loaded; + private bool _isLoading; /// /// Initializes a new instance of the class. @@ -49,9 +50,11 @@ namespace Avalonia.Markup.Xaml.Styling { if (_loaded == null) { + _isLoading = true; var loader = new AvaloniaXamlLoader(); var loaded = (IStyle)loader.Load(Source, _baseUri); _loaded = new[] { loaded }; + _isLoading = false; } return _loaded?[0]!; @@ -84,7 +87,7 @@ namespace Avalonia.Markup.Xaml.Styling public bool TryGetResource(object key, out object? value) { - if (Loaded is IResourceProvider p) + if (!_isLoading && Loaded is IResourceProvider p) { return p.TryGetResource(key, out value); } diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/ResourceIncludeTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/ResourceIncludeTests.cs index 7ab6c2de40..1514d5bd95 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/ResourceIncludeTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/ResourceIncludeTests.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Avalonia.Controls; using Avalonia.Media; using Avalonia.UnitTests; @@ -44,6 +45,43 @@ namespace Avalonia.Markup.Xaml.UnitTests.MakrupExtensions } } + [Fact] + public void Missing_ResourceKey_In_ResourceInclude_Does_Not_Cause_StackOverflow() + { + var styleXaml = @" + + +"; + + using (StartWithResources(("test:style.xaml", styleXaml))) + { + var xaml = @" + + + + + + + + +"; + + var loader = new AvaloniaXamlLoader(); + var app = Application.Current; + + try + { + loader.Load(xaml, null, app); + } + catch (KeyNotFoundException) + { + + } + } + } + private IDisposable StartWithResources(params (string, string)[] assets) { var assetLoader = new MockAssetLoader(assets); diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/StyleIncludeTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/StyleIncludeTests.cs new file mode 100644 index 0000000000..dca936d229 --- /dev/null +++ b/tests/Avalonia.Markup.Xaml.UnitTests/StyleIncludeTests.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using Avalonia.UnitTests; +using Xunit; + +namespace Avalonia.Markup.Xaml.UnitTests +{ + public class StyleIncludeTests : XamlTestBase + { + [Fact] + public void Missing_ResourceKey_In_StyleInclude_Does_Not_Cause_StackOverflow() + { + var styleXaml = @" +"; + + using (StartWithResources(("test:style.xaml", styleXaml))) + { + var xaml = @" + + + + +"; + + var loader = new AvaloniaXamlLoader(); + var app = Application.Current; + + try + { + loader.Load(xaml, null, app); + } + catch (KeyNotFoundException) + { + + } + } + } + + private IDisposable StartWithResources(params (string, string)[] assets) + { + var assetLoader = new MockAssetLoader(assets); + var services = new TestServices(assetLoader: assetLoader); + return UnitTestApplication.Start(services); + } + } +}