Repository navigation
fix(windows): recycle menu command ids to keep them within 16 bits - #430
Merged
Merged
Conversation
Member
|
this is a niche use-case, but I decided to fix it nonetheless. I decided to go with a different approach by using a wrapping Atomic instead of a mutex and recycling dropped IDs. I recommend in your app to stop recreating menu items and find a better way to reuse existing items. Hitting the 64.5k is wild and should never happen. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
On Windows, menu items stop working once a process has created about 64.5k menus and items in total. The menu still opens, but clicks do nothing: no
MenuEvent, no error.Why: command ids come from a global counter that starts at 1000 and only ever goes up. Items are inserted with the full
u32id, butWM_COMMANDis matched onLOWORD(wParam), so once the counter passes0xFFFFnothing matches anymore.ACCEL::cmdis 16-bit too.64.5k sounds like a lot, but apps that rebuild their tray menu on every state change get there. We hit it in Clash Verge Rev: the tray lists proxy nodes and gets rebuilt on every switch, and after a few hours Quit and then every other tray item stopped working.
Fix: hand out fresh ids up to
u16::MAXlike today, then reuse ids from dropped menus and items, oldest first. Nothing changes until the first ~64.5k ids are used up.A few notes:
WM_COMMANDstill queued for a dropped item could in theory land on a new item that got its id. With oldest-first reuse, that takes tens of thousands of allocations between the click and its dispatch, so I think it's fine. Today every click past0xFFFFis lost anyway.remove_atusesMF_BYCOMMAND, which also searches submenus, so it can remove the wrong row when an item sits in a menu and in one of its submenus. Can be fixed separately.muda = "0.20". Any chance of a 0.20.x backport?Testing
u16::MAXboundary (kept small so it's quick under Miri).-D warnings) and tests pass on Windows 11.dev, the click on the item with id 65536 is lost, and after that every click is; with this PR they all go through.Related: clash-verge-rev/clash-verge-rev#8159 (reproduced and verified). Probably the same bug: clash-verge-rev/clash-verge-rev#7131, clash-verge-rev/clash-verge-rev#6738, clash-verge-rev/clash-verge-rev#5520, clash-verge-rev/clash-verge-rev#6604, clash-verge-rev/clash-verge-rev#7095.
Repro
Output on
dev(9d35d84):With this PR: