Browse Source

Merge pull request #4007 from AvaloniaUI/fixes/stackoverflow-loading-resource

prevent so with ResourceInclude and StyleInclude.
pull/4017/head
Dariusz Komosiński 6 years ago
committed by GitHub
parent
commit
db5319c762
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 11
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ResourceInclude.cs
  2. 5
      src/Markup/Avalonia.Markup.Xaml/Styling/StyleInclude.cs
  3. 38
      tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/ResourceIncludeTests.cs
  4. 52
      tests/Avalonia.Markup.Xaml.UnitTests/StyleIncludeTests.cs

11
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;
/// <summary>
/// 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);

5
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;
/// <summary>
/// Initializes a new instance of the <see cref="StyleInclude"/> 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);
}

38
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 = @"
<ResourceDictionary xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<StaticResource x:Key='brush' ResourceKey='missing' />
</ResourceDictionary>";
using (StartWithResources(("test:style.xaml", styleXaml)))
{
var xaml = @"
<Application xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceInclude Source='test:style.xaml'/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>";
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);

52
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 = @"
<Style xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<Style.Resources>
<StaticResource x:Key='brush' ResourceKey='missing' />
</Style.Resources>
</Style>";
using (StartWithResources(("test:style.xaml", styleXaml)))
{
var xaml = @"
<Application xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<Application.Styles>
<StyleInclude Source='test:style.xaml'/>
</Application.Styles>
</Application>";
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);
}
}
}
Loading…
Cancel
Save