Avalonia icon indicating copy to clipboard operation
Avalonia copied to clipboard

stack overflow in binding system

Open busitech opened this issue 6 months ago • 14 comments

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()

busitech avatar Aug 21 '24 02:08 busitech