From 51f2d35a9653b0c80aa2a61b276ae92044b83d84 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Fri, 13 Sep 2024 09:52:49 -0500 Subject: [PATCH] [xaml] fix potential NRE in `{Binding}` Fixes: https://github.com/dotnet/maui/issues/24740 Using this in a project: Then, in a XAML file: xmlns:dg="clr-namespace:Maui.DataGrid;assembly=Maui.DataGrid" ... Would crash with: [0:] [13:46:57 FTL] Inner Exception: System.NullReferenceException: Object reference not set to an instance of an object. at Microsoft.Maui.Controls.Xaml.BindingExtension..ProvideValue>g__CreateBinding|40_0(<>c__DisplayClass40_0& ) in /_/src/Controls/src/Xaml/MarkupExtensions/BindingExtension.cs:line 46 at Microsoft.Maui.Controls.Xaml.BindingExtension.Microsoft.Maui.Controls.Xaml.IMarkupExtension.ProvideValue(IServiceProvider serviceProvider) in /_/src/Controls/src/Xaml/MarkupExtensions/BindingExtension.cs:line 27 at Maui.DataGrid.DataGrid.InitializeComponent() in D:\Maui.DataGrid\Maui.DataGrid\Microsoft.Maui.Controls.SourceGen\Microsoft.Maui.Controls.SourceGen.CodeBehindGenerator\DataGrid.xaml.sg.cs:line 53 at Maui.DataGrid.DataGrid..ctor() in D:\Maui.DataGrid\Maui.DataGrid\DataGrid.xaml.cs:line 46 at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Constructor(Object obj, IntPtr* args) at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr) Inspecting the IL, I see: BindingBase val115 = ((IMarkupExtension)(object)val31).ProvideValue((IServiceProvider)null); So, it is indeed passed a `null` `IServiceProvider`. Introduce a unit test and check for `null` as a fix. --- .../src/Xaml/MarkupExtensions/BindingExtension.cs | 3 ++- .../tests/Xaml.UnitTests/BindingExtensionTests.cs | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 src/Controls/tests/Xaml.UnitTests/BindingExtensionTests.cs diff --git a/src/Controls/src/Xaml/MarkupExtensions/BindingExtension.cs b/src/Controls/src/Xaml/MarkupExtensions/BindingExtension.cs index 552b8c6627b6..bbbe745a889e 100644 --- a/src/Controls/src/Xaml/MarkupExtensions/BindingExtension.cs +++ b/src/Controls/src/Xaml/MarkupExtensions/BindingExtension.cs @@ -43,7 +43,8 @@ BindingBase IMarkupExtension.ProvideValue(IServiceProvider serviceP BindingBase CreateBinding() { Type bindingXDataType = null; - if ((serviceProvider.GetService(typeof(IXamlTypeResolver)) is IXamlTypeResolver typeResolver) + if (serviceProvider is not null && + (serviceProvider.GetService(typeof(IXamlTypeResolver)) is IXamlTypeResolver typeResolver) && (serviceProvider.GetService(typeof(IXamlDataTypeProvider)) is IXamlDataTypeProvider dataTypeProvider) && dataTypeProvider.BindingDataType != null) { diff --git a/src/Controls/tests/Xaml.UnitTests/BindingExtensionTests.cs b/src/Controls/tests/Xaml.UnitTests/BindingExtensionTests.cs new file mode 100644 index 000000000000..2bd83b0ab410 --- /dev/null +++ b/src/Controls/tests/Xaml.UnitTests/BindingExtensionTests.cs @@ -0,0 +1,14 @@ +using NUnit.Framework; + +namespace Microsoft.Maui.Controls.Xaml.UnitTests; + +[TestFixture] +public class BindingExtensionTests +{ + [Test] + public void ProvideValue_Null() + { + IMarkupExtension binding = new BindingExtension { Path = "Foo" }; + binding.ProvideValue(null); // This should not throw + } +}