Browse Source

Wrap type conversions in try-catch to prevent crashes due to unhandled exceptions (#15640)

pull/15666/head
Bartosz Korczyński 2 years ago
committed by GitHub
parent
commit
93d2140cc0
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 36
      src/Avalonia.Base/Data/Core/TargetTypeConverter.cs
  2. 37
      tests/Avalonia.Controls.UnitTests/TextBoxTests_DataValidation.cs

36
src/Avalonia.Base/Data/Core/TargetTypeConverter.cs

@ -76,16 +76,32 @@ internal abstract class TargetTypeConverter
if (toTypeConverter.CanConvertFrom(from))
{
result = toTypeConverter.ConvertFrom(null, culture, value);
return true;
try
{
result = toTypeConverter.ConvertFrom(null, culture, value);
return true;
}
catch
{
result = null;
return false;
}
}
var fromTypeConverter = TypeDescriptor.GetConverter(from);
if (fromTypeConverter.CanConvertTo(t))
{
result = fromTypeConverter.ConvertTo(null, culture, value, t);
return true;
try
{
result = fromTypeConverter.ConvertTo(null, culture, value, t);
return true;
}
catch
{
result = null;
return false;
}
}
// TODO: This requires reflection: we probably need to make compiled bindings emit
@ -95,8 +111,16 @@ internal abstract class TargetTypeConverter
t,
OperatorType.Implicit | OperatorType.Explicit) is { } cast)
{
result = cast.Invoke(null, new[] { value });
return true;
try
{
result = cast.Invoke(null, new[] { value });
return true;
}
catch
{
result = null;
return false;
}
}
#pragma warning restore IL2067
#pragma warning restore IL2026

37
tests/Avalonia.Controls.UnitTests/TextBoxTests_DataValidation.cs

@ -6,8 +6,11 @@ using System.Linq;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Templates;
using Avalonia.Data;
using Avalonia.Data.Core;
using Avalonia.Headless;
using Avalonia.Markup.Data;
using Avalonia.Markup.Xaml.MarkupExtensions;
using Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings;
using Avalonia.Platform;
using Avalonia.UnitTests;
using Moq;
@ -110,6 +113,40 @@ namespace Avalonia.Controls.UnitTests
}
}
[Fact]
public void CompiledBindings_TypeConverter_Exceptions_Should_Set_DataValidationErrors_HasErrors()
{
var path = new CompiledBindingPathBuilder()
.Property(
new ClrPropertyInfo(
nameof(ExceptionTest.LessThan10),
target => ((ExceptionTest)target).LessThan10,
(target, value) => ((ExceptionTest)target).LessThan10 = (int)value,
typeof(int)),
PropertyInfoAccessorFactory.CreateInpcPropertyAccessor)
.Build();
using (UnitTestApplication.Start(Services))
{
var target = new TextBox
{
DataContext = new ExceptionTest(),
[!TextBox.TextProperty] = new CompiledBindingExtension
{
Source = new ExceptionTest(),
Path = path,
Mode = BindingMode.TwoWay
},
Template = CreateTemplate(),
};
target.ApplyTemplate();
target.Text = "a";
Assert.True(DataValidationErrors.GetHasErrors(target));
}
}
private static TestServices Services => TestServices.MockThreadingInterface.With(
standardCursorFactory: Mock.Of<ICursorFactory>(),
textShaperImpl: new HeadlessTextShaperStub(),

Loading…
Cancel
Save