InvalidOperationException in AdornmentLayer

SyntaxEditor for WPF Forum

Posted 1 year ago by Tobias Lingemann - Software Devolpment Engineer, Vector Informatik GmbH
Version: 22.1.1
Platform: .NET 4.8
Environment: Windows 10 (64-bit)
Avatar

Hi,

we received a crash report from a customer:

Unhandled Exception:System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
   at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
   at System.Collections.Generic.List`1.Enumerator.MoveNextRare()
   at ActiproSoftware.Internal.GT0.Draw(TextViewDrawContext  )
   at ActiproSoftware.Internal.CT4.vhu(TextViewDrawContext  )
   at ActiproSoftware.Internal.CT4.Nhn(CanvasDrawEventArgs  )
   at ActiproSoftware.Windows.Controls.SyntaxEditor.Primitives.TextView.Sni(Object  , CanvasDrawEventArgs  )
   at ActiproSoftware.Windows.Controls.Rendering.CanvasControl.mli(DrawingContext  )
   at ActiproSoftware.Windows.Controls.Rendering.CanvasControl.OnRender(DrawingContext drawingContext)
   at System.Windows.UIElement.Arrange(Rect finalRect)
   at System.Windows.ContextLayoutManager.UpdateLayout()
   at System.Windows.ContextLayoutManager.UpdateLayoutCallback(Object arg)
   at System.Windows.Media.MediaContext.FireInvokeOnRenderCallbacks()
   at System.Windows.Media.MediaContext.RenderMessageHandlerCore(Object resizedCompositionTarget)
   at System.Windows.Media.MediaContext.RenderMessageHandler(Object resizedCompositionTarget)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.DispatcherOperation.InvokeImpl()
   at MS.Internal.CulturePreservingExecutionContext.CallbackWrapper(Object obj)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at MS.Internal.CulturePreservingExecutionContext.Run(CulturePreservingExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Windows.Threading.DispatcherOperation.Invoke()
   at System.Windows.Threading.Dispatcher.ProcessQueue()
   at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
   at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
   at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
   at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
   at System.Windows.Application.RunDispatcher(Object ignore)
   at System.Windows.Application.RunInternal(Window window)
   at Vector.ITE.Backbone.Startup.SingleInstanceApp.Run(String[] instanceArgs)
   at CAPLBrowser.App.CbrBootstrapper.$_executor_Run(String[] commandLineArgs, Container container)
   at CAPLBrowser.App.CbrBootstrapper.Run(String[] commandLineArgs, Container container)
   at Vector.ITE.Modularity.BootstrapperBase.RunCore(AssemblyCatalog assemblyCatalog, String cacheFile, ApplicationScope applicationScope, ApplicationMode applicationMode, String[] commandLineArgs)
   at CAPLBrowser.App.Program.Main(String[] args)
   at CAPLBrowser.App.Program.Main(String[] args) 

The version the customer is using is 22.1.1, but we already upgraded to 22.1.4. However I could not find any matching description in the anouncement posts, so I assume the problem still exists.

I looked at the code and it seems the problem occurs in the Draw callback of the AdornmentLayer.

My best guess is that, since the squiggle error tags are created in the parser thread, this collides with the rendering process in the UI thread.


Best regards, Tobias Lingemann.

Comments (3)

Posted 1 year ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hi Tobias,

From looking at the stack trace and deobfuscating it for v22.1.1, I believe that the method the exception occurs in is AdornmentLayout.Draw where it loops through the adornments in the layer and renders them.  As you said, something must be invoking a change to the adornments collection from another thread here.

I did some debugging on our end and while squiggle tags are updated in another thread, the notification to change adornments ends up happening on the main thread.  I also went through all our Adornments samples and none of them seemed to do any updating of adornments on anything except the main UI thread.  We haven't had any reports of issues in this area either.

Is there anywhere else in your code where you might be doing some updating of adornments from a different thread?  If so, please invoke those updates to the main UI thread instead.


Actipro Software Support

Posted 1 year ago by Tobias Lingemann - Software Devolpment Engineer, Vector Informatik GmbH
Avatar

Hm, not really. I only know that the outlining is also updated via the parse thread. But this seems to use the same invoke mechanism.

We also use the standard DelimiterHighlightTagger. I don't think this could cause the issue.

Additionally we have a custom tagger which highlights occurrences of the currently selected word, but this only runs in the main thread.

The customer reported that the crash can happend during editing the file, but also when the app is just idling in the background. In the later case there shouldn't be any updates coming from the background threads. So I readlly don't know waht could cause this issue.


Best regards, Tobias Lingemann.

Posted 1 year ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hi Tobias,

I agree, the highlight taggers should also occur in the main UI thread.  And you wouldn't think that anything would be updating adornments when the app is idling.  

In terms of trying to narrow things down, I wonder if there is a way that when the exception occurs, you could also log the stack traces of other threads so that we could see what is triggering an adornment update, assuming that is the root cause here?


Actipro Software Support

The latest build of this product (v24.1.2) was released 4 days ago, which was after the last post in this thread.

Add Comment

Please log in to a validated account to post comments.