[Windows] Destroying a Menu or MenuItem aborts the process
What happens
On Windows, freeing a Menu or a MenuItem kills the process. It makes no difference whether Dart's
garbage collector frees the handle or the program calls dispose() itself. The abort is
0xc0000409 (fast-fail 7) in ucrtbase.dll, and stderr carries no message, unlike the click fault in
#52, which printed a clear one.
This is separate from #52 and survives the fix proposed there.
Reproduce
A small Flutter app on nativeapi-flutter 0.2.4, Flutter 3.41.2, Windows 11, release build, with the
menu opened by a real right-click. Each open builds a menu of 15 items with three submenus, so about 23
handles in total. I forced a major collection between opens to remove timing luck.
| what the app does with the previous menu |
outcome |
| rebuilds each open, lets the collector free the old one |
dies on the second pick, 2 runs of 2 |
rebuilds each open, calls dispose() on the old one first |
dies on the second pick, 2 runs of 2 |
| rebuilds each open, keeps every old menu alive |
survived 6 picks, 2 runs of 2 |
| builds one menu and reuses it |
survived 6 picks, 2 runs of 2 |
I added prints to menu_windows.cpp to see the order. Every crashing run ends the same way, on the last
~MenuItem::Impl of the previous menu, with no further output.
Opening the menu matters too. When the app opened its own menu from a timer or a local HTTP handler, the
same build survived 48 picks. Only a real right-click, which reaches the menu through Flutter's pointer
handling, produced the crash.
A lead, offered as a guess rather than a finding
WindowMessageDispatcher::DispatchWindowProc copies the handler list, then calls the handlers with the
lock released. A menu destroyed while that copy is being walked leaves a handler pointing at an object
that is gone. That would fit what I see: destruction during menu activity, an abort with no message, and
no crash at all when nothing is ever destroyed. I have not proved it, and the trace prints do not reach
far enough to say.
Workaround for now
Build menus once and never let one be destroyed. Rebuilding is safe as long as the old menus stay alive,
though on Windows that leaks a menu handle each time.
I have a reproduction ready and I am happy to test any patch you would like to try.
[Windows] Destroying a Menu or MenuItem aborts the process
What happens
On Windows, freeing a
Menuor aMenuItemkills the process. It makes no difference whether Dart'sgarbage collector frees the handle or the program calls
dispose()itself. The abort is0xc0000409(fast-fail 7) inucrtbase.dll, and stderr carries no message, unlike the click fault in#52, which printed a clear one.
This is separate from #52 and survives the fix proposed there.
Reproduce
A small Flutter app on nativeapi-flutter 0.2.4, Flutter 3.41.2, Windows 11, release build, with the
menu opened by a real right-click. Each open builds a menu of 15 items with three submenus, so about 23
handles in total. I forced a major collection between opens to remove timing luck.
dispose()on the old one firstI added prints to
menu_windows.cppto see the order. Every crashing run ends the same way, on the last~MenuItem::Implof the previous menu, with no further output.Opening the menu matters too. When the app opened its own menu from a timer or a local HTTP handler, the
same build survived 48 picks. Only a real right-click, which reaches the menu through Flutter's pointer
handling, produced the crash.
A lead, offered as a guess rather than a finding
WindowMessageDispatcher::DispatchWindowProccopies the handler list, then calls the handlers with thelock released. A menu destroyed while that copy is being walked leaves a handler pointing at an object
that is gone. That would fit what I see: destruction during menu activity, an abort with no message, and
no crash at all when nothing is ever destroyed. I have not proved it, and the trace prints do not reach
far enough to say.
Workaround for now
Build menus once and never let one be destroyed. Rebuilding is safe as long as the old menus stay alive,
though on Windows that leaks a menu handle each time.
I have a reproduction ready and I am happy to test any patch you would like to try.