BWindow: Fix confusion between modifiers and "prepared modifiers".

The former must have B_NO_COMMAND_KEY if the shortcut has no command key,
while the latter should simply not have B_COMMAND_KEY.

This mixup meant that modifiers flags without either set were
passed back to BMenuItem, which then used them when calling
RemoveShortcut(), but that method expects B_NO_COMMAND_KEY
to be specified, so the shortcuts weren't really removed,
resulting in use-after-frees.

Fixes #19426 and related issues.
This commit is contained in:
Augustin Cavalier
2025-10-10 16:20:03 -04:00
parent 4ccb957d6c
commit 9359d0860b
+18 -9
View File
@@ -97,10 +97,11 @@ public:
BMessage* message, BHandler* target); BMessage* message, BHandler* target);
~Shortcut(); ~Shortcut();
bool Matches(uint32 key, uint32 modifiers) const; bool Matches(uint32 key, uint32 preparedModifiers) const;
uint32 Key() const { return fKey; }; uint32 Key() const { return fKey; };
uint32 Modifiers() const { return fModifiers; }; uint32 Modifiers() const;
uint32 PreparedModifiers() const { return fPreparedModifiers; };
BMenuItem* MenuItem() const { return fMenuItem; } BMenuItem* MenuItem() const { return fMenuItem; }
BMessage* Message() const { return fMessage; } BMessage* Message() const { return fMessage; }
BHandler* Target() const { return fTarget; } BHandler* Target() const { return fTarget; }
@@ -111,7 +112,7 @@ public:
private: private:
uint32 fKey; uint32 fKey;
uint32 fModifiers; uint32 fPreparedModifiers;
BMenuItem* fMenuItem; BMenuItem* fMenuItem;
BMessage* fMessage; BMessage* fMessage;
BHandler* fTarget; BHandler* fTarget;
@@ -244,7 +245,7 @@ BWindow::unpack_cookie::unpack_cookie()
BWindow::Shortcut::Shortcut(uint32 key, uint32 modifiers, BMenuItem* item) BWindow::Shortcut::Shortcut(uint32 key, uint32 modifiers, BMenuItem* item)
: :
fKey(PrepareKey(key)), fKey(PrepareKey(key)),
fModifiers(PrepareModifiers(modifiers)), fPreparedModifiers(PrepareModifiers(modifiers)),
fMenuItem(item), fMenuItem(item),
fMessage(NULL), fMessage(NULL),
fTarget(NULL) fTarget(NULL)
@@ -256,7 +257,7 @@ BWindow::Shortcut::Shortcut(uint32 key, uint32 modifiers, BMessage* message,
BHandler* target) BHandler* target)
: :
fKey(PrepareKey(key)), fKey(PrepareKey(key)),
fModifiers(PrepareModifiers(modifiers)), fPreparedModifiers(PrepareModifiers(modifiers)),
fMenuItem(NULL), fMenuItem(NULL),
fMessage(message), fMessage(message),
fTarget(target) fTarget(target)
@@ -272,9 +273,17 @@ BWindow::Shortcut::~Shortcut()
bool bool
BWindow::Shortcut::Matches(uint32 key, uint32 modifiers) const BWindow::Shortcut::Matches(uint32 key, uint32 preparedModifiers) const
{ {
return fKey == key && fModifiers == modifiers; return fKey == key && fPreparedModifiers == preparedModifiers;
}
uint32
BWindow::Shortcut::Modifiers() const
{
return fPreparedModifiers
| (((fPreparedModifiers & B_COMMAND_KEY) == 0) ? B_NO_COMMAND_KEY : 0);
} }
@@ -3897,12 +3906,12 @@ BWindow::Shortcut*
BWindow::_FindShortcut(uint32 key, uint32 modifiers) BWindow::_FindShortcut(uint32 key, uint32 modifiers)
{ {
key = Shortcut::PrepareKey(key); key = Shortcut::PrepareKey(key);
modifiers = Shortcut::PrepareModifiers(modifiers); uint32 preparedModifiers = Shortcut::PrepareModifiers(modifiers);
int32 shortcutCount = fShortcuts.CountItems(); int32 shortcutCount = fShortcuts.CountItems();
for (int32 index = 0; index < shortcutCount; index++) { for (int32 index = 0; index < shortcutCount; index++) {
Shortcut* shortcut = (Shortcut*)fShortcuts.ItemAt(index); Shortcut* shortcut = (Shortcut*)fShortcuts.ItemAt(index);
if (shortcut != NULL && shortcut->Matches(key, modifiers)) if (shortcut != NULL && shortcut->Matches(key, preparedModifiers))
return shortcut; return shortcut;
} }