Avalonia
Avalonia copied to clipboard
stack overflow in binding system
Describe the bug
We are observing a stack overflow, caused by a loop in the binding code. Below are two full iterations of the loop that leads to the stack overflow.
To Reproduce
This issue is very easy to recreate. Adding a MaskedTextBox to a page bound to a string that has an initial value that does not conform to the format of the mask (including null or empty string) will immediately cause a stack overflow when the application starts.
Expected behavior
No stack overflow is expected.
Avalonia version
nightly build 11.2.999-cibuild0051406-alpha last known good version is 11.0.13
OS
macOS
Additional context
at Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings.InpcPropertyAccessor.SetValue(System.Object, Avalonia.Data.BindingPriority)
at Avalonia.Data.Core.Plugins.DataValidationBase.SetValue(System.Object, Avalonia.Data.BindingPriority)
at Avalonia.Data.Core.Plugins.ExceptionValidationPlugin+Validator.SetValue(System.Object, Avalonia.Data.BindingPriority)
at Avalonia.Data.Core.ExpressionNodes.PropertyAccessorNode.WriteValueToSource(System.Object, System.Collections.Generic.IReadOnlyList`1<Avalonia.Data.Core.ExpressionNodes.ExpressionNode>)
at Avalonia.Data.Core.BindingExpression.WriteValueToSource(System.Object)
at Avalonia.Data.Core.BindingExpression.OnTargetPropertyChanged(System.Object, Avalonia.AvaloniaPropertyChangedEventArgs)
at Avalonia.AvaloniaObject.RaisePropertyChanged(Avalonia.AvaloniaProperty`1<System.__Canon>, Avalonia.Data.Optional`1<System.__Canon>, Avalonia.Data.BindingValue`1<System.__Canon>, Avalonia.Data.BindingPriority, Boolean)
at Avalonia.PropertyStore.EffectiveValue`1.SetAndRaiseCore(Avalonia.PropertyStore.ValueStore, Avalonia.StyledProperty`1<System.__Canon>, System.__Canon, Avalonia.Data.BindingPriority, Boolean, Boolean)
at Avalonia.PropertyStore.EffectiveValue`1.SetLocalValueAndRaise(Avalonia.PropertyStore.ValueStore, Avalonia.StyledProperty`1<System.__Canon>, System.__Canon)
at Avalonia.PropertyStore.EffectiveValue`1.SetLocalValueAndRaise(Avalonia.PropertyStore.ValueStore, Avalonia.AvaloniaProperty, System.Object)
at Avalonia.PropertyStore.ValueStore.SetLocalValue(Avalonia.AvaloniaProperty, System.Object)
at Avalonia.PropertyStore.ValueStore.Avalonia.Data.Core.IBindingExpressionSink.OnChanged(Avalonia.Data.Core.UntypedBindingExpressionBase, Boolean, Boolean, System.Object, Avalonia.Data.Core.BindingError)
at Avalonia.Data.Core.UntypedBindingExpressionBase.PublishValue(System.Object, Avalonia.Data.Core.BindingError)
at Avalonia.Data.Core.BindingExpression.ConvertAndPublishValue(System.Object, Avalonia.Data.Core.BindingError)
at Avalonia.Data.Core.BindingExpression.OnNodeValueChanged(Int32, System.Object, System.Exception)
at Avalonia.Data.Core.ExpressionNodes.ExpressionNode.SetValue(System.Object, System.Exception)
at Avalonia.Data.Core.ExpressionNodes.ExpressionNode.SetValue(System.Object)
at Avalonia.Data.Core.ExpressionNodes.ExpressionNode.SetValue(System.Object)
at Avalonia.Data.Core.ExpressionNodes.PropertyAccessorNode.OnValueChanged(System.Object)
at Avalonia.Data.Core.Plugins.PropertyAccessorBase.PublishValue(System.Object)
at Avalonia.Data.Core.Plugins.DataValidationBase.InnerValueChanged(System.Object)
at Avalonia.Data.Core.Plugins.PropertyAccessorBase.PublishValue(System.Object)
at Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings.InpcPropertyAccessor.SendCurrentValue()
Now the loop starts over....
at Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings.InpcPropertyAccessor.SetValue(System.Object, Avalonia.Data.BindingPriority)
at Avalonia.Data.Core.Plugins.DataValidationBase.SetValue(System.Object, Avalonia.Data.BindingPriority)
at Avalonia.Data.Core.Plugins.ExceptionValidationPlugin+Validator.SetValue(System.Object, Avalonia.Data.BindingPriority)
at Avalonia.Data.Core.ExpressionNodes.PropertyAccessorNode.WriteValueToSource(System.Object, System.Collections.Generic.IReadOnlyList`1<Avalonia.Data.Core.ExpressionNodes.ExpressionNode>)
at Avalonia.Data.Core.BindingExpression.WriteValueToSource(System.Object)
at Avalonia.Data.Core.BindingExpression.OnTargetPropertyChanged(System.Object, Avalonia.AvaloniaPropertyChangedEventArgs)
at Avalonia.AvaloniaObject.RaisePropertyChanged(Avalonia.AvaloniaProperty`1<System.__Canon>, Avalonia.Data.Optional`1<System.__Canon>, Avalonia.Data.BindingValue`1<System.__Canon>, Avalonia.Data.BindingPriority, Boolean)
at Avalonia.PropertyStore.EffectiveValue`1.SetAndRaiseCore(Avalonia.PropertyStore.ValueStore, Avalonia.StyledProperty`1<System.__Canon>, System.__Canon, Avalonia.Data.BindingPriority, Boolean, Boolean)
at Avalonia.PropertyStore.EffectiveValue`1.SetLocalValueAndRaise(Avalonia.PropertyStore.ValueStore, Avalonia.StyledProperty`1<System.__Canon>, System.__Canon)
at Avalonia.PropertyStore.EffectiveValue`1.SetLocalValueAndRaise(Avalonia.PropertyStore.ValueStore, Avalonia.AvaloniaProperty, System.Object)
at Avalonia.PropertyStore.ValueStore.SetLocalValue(Avalonia.AvaloniaProperty, System.Object)
at Avalonia.PropertyStore.ValueStore.Avalonia.Data.Core.IBindingExpressionSink.OnChanged(Avalonia.Data.Core.UntypedBindingExpressionBase, Boolean, Boolean, System.Object, Avalonia.Data.Core.BindingError)
at Avalonia.Data.Core.UntypedBindingExpressionBase.PublishValue(System.Object, Avalonia.Data.Core.BindingError)
at Avalonia.Data.Core.BindingExpression.ConvertAndPublishValue(System.Object, Avalonia.Data.Core.BindingError)
at Avalonia.Data.Core.BindingExpression.OnNodeValueChanged(Int32, System.Object, System.Exception)
at Avalonia.Data.Core.ExpressionNodes.ExpressionNode.SetValue(System.Object, System.Exception)
at Avalonia.Data.Core.ExpressionNodes.ExpressionNode.SetValue(System.Object)
at Avalonia.Data.Core.ExpressionNodes.ExpressionNode.SetValue(System.Object)
at Avalonia.Data.Core.ExpressionNodes.PropertyAccessorNode.OnValueChanged(System.Object)
at Avalonia.Data.Core.Plugins.PropertyAccessorBase.PublishValue(System.Object)
at Avalonia.Data.Core.Plugins.DataValidationBase.InnerValueChanged(System.Object)
at Avalonia.Data.Core.Plugins.PropertyAccessorBase.PublishValue(System.Object)
at Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings.InpcPropertyAccessor.SendCurrentValue()
The loop is kicked off initially by this statement:
at Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings.InpcPropertyAccessor.SubscribeCore()