Bugzilla – Bug 539138
InvalidOperationException when trying to launch columnheader.py sample
Last modified: 2009-09-15 20:13:20 UTC
[Debug 17:49:18.492] AutomationBridge: Creating new UiaAtkBridge.TreeItem adapter for Mono.UIAutomation.Winforms.ListViewProvider+ListViewListItemEditProvider Exception in Gtk# callback delegate Note: Applications can use GLib.ExceptionManager.UnhandledException to handle the exception. System.InvalidOperationException: Collection was modified;enumeration operation may not execute. at System.Collections.Generic.List`1+Enumerator[Mono.UIAutomation.Winforms.FragmentControlProvider].MoveNext () [0x00000] at Mono.UIAutomation.Winforms.FragmentControlProvider+<GetEnumerator>c__Iterator0.MoveNext () [0x00078] in /home/knocte/Documents/iDocs/Proyectos/mono/a11y/uia2atkMAKE/UIAutomationWinforms/UIAutomationWinforms/Mono.UIAutomation.Winforms/FragmentControlProvider.cs:152 at Mono.UIAutomation.Winforms.ListViewProvider+ListViewGroupProvider.get_ItemsBoundingRectangle () [0x00041] in /home/knocte/Documents/iDocs/Proyectos/mono/a11y/uia2atkMAKE/UIAutomationWinforms/UIAutomationWinforms/Mono.UIAutomation.Winforms/ListViewProvider.cs:687 at Mono.UIAutomation.Winforms.ListViewProvider+ListViewGroupProvider.GetProviderPropertyValue (Int32 propertyId) [0x0003e] in /home/knocte/Documents/iDocs/Proyectos/mono/a11y/uia2atkMAKE/UIAutomationWinforms/UIAutomationWinforms/Mono.UIAutomation.Winforms/ListViewProvider.cs:652 at Mono.UIAutomation.Winforms.SimpleControlProvider.GetPropertyValue (Int32 propertyId) [0x0004d] in /home/knocte/Documents/iDocs/Proyectos/mono/a11y/uia2atkMAKE/UIAutomationWinforms/UIAutomationWinforms/Mono.UIAutomation.Winforms/SimpleControlProvider.cs:399 at UiaAtkBridge.Adapter.OnRefStateSet () [0x000bf] in /home/knocte/Documents/iDocs/Proyectos/mono/a11y/uia2atkMAKE/UiaAtkBridge/UiaAtkBridge/Adapter.cs:219 at UiaAtkBridge.ComponentParentAdapter.OnRefStateSet () [0x00000] in /home/knocte/Documents/iDocs/Proyectos/mono/a11y/uia2atkMAKE/UiaAtkBridge/UiaAtkBridge/ComponentParentAdapter.cs:144 at Atk.Object.RefStateSet_cb (IntPtr raw) [0x0000d] in /home/knocte/Documents/iDocs/Proyectos/mono/a11y/gtk-sharp/atk/generated/Object.custom:128 at GLib.ExceptionManager.RaiseUnhandledException(System.Exception e, Boolean is_terminal) in /home/knocte/Documents/iDocs/Proyectos/mono/a11y/gtk-sharp/glib/ExceptionManager.cs:line 58 at Atk.Object.RefStateSet_cb(IntPtr raw) in /home/knocte/Documents/iDocs/Proyectos/mono/a11y/gtk-sharp/atk/generated/Object.custom:line 133 at GLib.MainLoop.g_main_loop_run(IntPtr ) at GLib.MainLoop.Run() in /home/knocte/Documents/iDocs/Proyectos/mono/a11y/gtk-sharp/glib/MainLoop.cs:line 59 at UiaAtkBridge.Monitor.GLibMainLoopThread() in /home/knocte/Documents/iDocs/Proyectos/mono/a11y/uia2atkMAKE/UiaAtkBridge/UiaAtkBridge/Monitor.cs:line 145
Threading bug (not deterministic). Published this patch in RB ( http://reviews.mono-a11y.org/r/450/diff/ ): Index: UIAutomationWinforms/UIAutomationWinforms/Mono.UIAutomation.Winforms/FragmentControlProvider.cs =================================================================== --- UIAutomationWinforms/UIAutomationWinforms/Mono.UIAutomation.Winforms/FragmentControlProvider.cs (revision 141771) +++ UIAutomationWinforms/UIAutomationWinforms/Mono.UIAutomation.Winforms/FragmentControlProvider.cs (working copy) @@ -149,7 +149,7 @@ public IEnumerator<FragmentControlProvider> GetEnumerator () { - foreach (FragmentControlProvider childProvider in children) + foreach (FragmentControlProvider childProvider in new List<FragmentControlProvider> (children)) yield return childProvider; } However, this led to a discussion in IRC: (03:55:43 PM) brad: knocte: hrm... I don't really see how this fixes the threading bug (03:55:58 PM) brad: yes, you're copying the children array, but it's still not thread safe (03:56:17 PM) brad: and copying the children array in GetEnumerator is going to be *really* expensive (03:56:45 PM) knocte: mmm (03:57:53 PM) knocte: I think it fixes the threading bug (I've seen code that does this) because it allows the collection to be modified while the copy is intact (03:58:02 PM) knocte: I'll check about the complexity though (03:58:21 PM) brad: unless the list is synchronized, copying the data while it is being modified could corrupt the data (03:59:05 PM) knocte: ok, then I didn't fix it completely; I fixed it for the case in which the data is being modified while inside the foreach loop, not while copying the data (03:59:17 PM) brad: yes, perhaps (03:59:36 PM) brad: but the right fix is to actually add locking (03:59:59 PM) knocte: but with what? the stacktrace doesn't give much more info (04:00:21 PM) knocte: with every member that access the collection? (04:01:19 PM) brad: well, I don't know about that specific instance (04:01:35 PM) brad: but modifying the children list while you're iterating it is a bad idea, if that is indeed what is happening (04:02:14 PM) brad: (again, I haven't seen the stack trace, so I can't comment on specifics) (04:02:30 PM) knocte: the stacktrace is on the bug referenced (04:03:43 PM) brad: eep... yeah, the only safe way to modify a list while you're iterating it is to iterate using indicies (04:04:22 PM) knocte: well, I would say, that may preven InvalidOperationExceptions, but would still cause IndexOutOfRangeExceptions (04:04:37 PM) knocte: or not, mm, not sure (04:04:49 PM) brad: if children is being modified as you're iterating it, yes (04:05:21 PM) brad: because you can't assume that once you check if the index is less than count, that that condition will exist during the block (04:05:38 PM) brad: thus, locking (04:06:05 PM) brad: *but* if you're modifying the children array while iterating, that's a different case (04:07:55 PM) knocte: ok, then as it's not trivial, let's write this on the bug and move on, this is in the end 1.0 work.. (04:09:20 PM) brad: nod So, as this is not trivial to fix, we're postponing it.