fix(inventory): guard Swap slot click against negative slot index (#2313)

The `Swap` branch of `internal_on_slot_click` indexed
`self.get_behaviour().slots[slot_index as usize]` without first checking
`slot_index >= 0`, unlike every sibling branch (Pickup, QuickMove, Throw,
Clone, QuickCraft) which all guard with `if slot_index < 0 { return; }`.

`slot_index` originates from the client `SClickSlot` packet (`i16` slot
field, widened to `i32`). The upstream validation in `Player::on_slot_click`
relies on `ScreenHandler::is_slot_valid`, whose check
`slot == -1 || slot == -999 || slot < slots.len() as i32` returns `true`
for ANY negative slot (a negative value is always `< slots.len()`), so
negative indices are not filtered out before reaching the handler. A
crafted Swap packet with a negative slot (e.g. -5) and a hotbar button in
`0..9` (or 40) therefore evaluated `slots[(-5) as usize]`, an enormous
index, causing an out-of-bounds Vec panic and crashing the server.

Add the same `if slot_index < 0 { return; }` guard at the top of the Swap
branch, matching the sibling branches exactly. Minimal, low-risk: legitimate
Swap clicks always carry a non-negative container slot, so behaviour is
unchanged for valid input.
This commit is contained in:
dongzh1
2026-07-01 19:43:54 +08:00
committed by GitHub
parent d8b7ae30a5
commit ae1813735b

View File

@@ -1223,6 +1223,9 @@ pub trait ScreenHandler: Send + Sync {
} else if action_type == SlotActionType::Swap && (0..9).contains(&button)
|| button == 40
{
if slot_index < 0 {
return;
}
let mut button_stack = player
.get_inventory()
.get_stack(button as usize)