Skip to content

Fix SetMenuColumnHeader not reaching players and out-of-bounds menu column access - #1290

Open
GuiBoneVowt wants to merge 2 commits into
openmultiplayer:masterfrom
GuiBoneVowt:fix-811-menu-column-header
Open

GuiBoneVowt wants to merge 2 commits into
openmultiplayer:masterfrom
GuiBoneVowt:fix-811-menu-column-header

Conversation

@GuiBoneVowt

Copy link
Copy Markdown

Fixes #811

Two small fixes in Server/Components/Menus/menu.hpp, one commit each:

  1. SetMenuColumnHeader did not update the menu for players who had already seen it. setColumnHeader was the only setter that did not reset initedFor_ (addCell, disableRow and disable do), so the next ShowMenuForPlayer did not resend the menu and the client kept the old header.
  2. A column index equal to the column count went out of bounds. The checks were column > columnCount, so column = 2 got through on a 2-column menu: setColumnHeader, addCell and getRowCount threw from .at(2) (logged as a native exception), and getColumnHeader / getCell used operator[] and read past the arrays. The new isValidColumn keeps the old rule (column <= columnCount) and also stays inside the 2-element arrays, so valid calls behave as before, including column 1 on a 1-column menu.

Testing

Windows, RelWithDebInfo, Win32 + ClangCL, on top of current master (72bf89c).

Headless gamemode, 2-column menu where column 0 row 0 holds a 15-character item:

Call master this PR
AddMenuItem(menu, 2, ...) exception invalid array<T, N> subscript, returns 0 returns -1, no exception
SetMenuColumnHeader(menu, 2, ...) exception, returns 0 ignored, no exception
GetMenuItems(menu, 2) exception, returns 0 0
GetMenuColumnHeader(menu, 2, ...) "\1\1NC0123456789ABCDE": the item counts, padding and the text of cell 0/0 ""
GetMenuItem(menu, 2, 0, ...) "" (also an out-of-bounds read) ""
Valid columns, and column 1 on a 1-column menu work work, same results

In game (SA-MP 0.3.7-R5 client), the same menu shown three times, 6 seconds apart, changing both headers with SetMenuColumnHeader before each ShowMenuForPlayer:

  • master: the menu keeps showing HEADER V1 / COL2 V1 on all three steps (tried three times).
  • This PR: the headers change to V2 and then V3.
In-game repro (core of the gamemode)
new Menu:gMenu;

public OnGameModeInit()
{
	gMenu = CreateMenu("Issue 811", 2, 200.0, 150.0, 120.0, 120.0);
	AddMenuItem(gMenu, 0, "Item A");
	AddMenuItem(gMenu, 1, "1");
	return 1;
}

// Called with step 1, 2 and 3, six seconds apart, after the player spawns.
ShowStep(playerid, step)
{
	new header[32];
	HideMenuForPlayer(gMenu, playerid);
	format(header, sizeof (header), "HEADER V%d", step);
	SetMenuColumnHeader(gMenu, 0, header);
	ShowMenuForPlayer(gMenu, playerid);
}

clang-format 13 with the repo's .clang-format: no changes.

Notes

  • SetMenuColumnHeader still returns true for an invalid column, because IMenu::setColumnHeader returns void and changing that touches the SDK.
  • Rejecting column 1 on 1-column menus too (column >= columnCount) would be a one-line change in isValidColumn, but it changes what AddMenuItem returns for scripts that do that today, so I kept the current behaviour. Happy to change it if you prefer.

setColumnHeader was the only menu setter that did not reset initedFor_,
so players that had already been sent the menu kept seeing the old header.
The column checks were "column > columnCount", so column 2 got through on a
2-column menu: setColumnHeader, addCell and getRowCount threw from .at(2), and
getColumnHeader and getCell read past columnHeaders and columnMenuItems.
Keep the old rule and also stay inside the arrays.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SetMenuColumnHeader

1 participant