[Bugfix] entity.at() lazy init guard also has gridstate.size()==0 bug #278

Closed
opened 2026-03-07 23:26:00 +00:00 by john · 0 comments
Owner

Summary

UIEntity::at() (entity.at(x, y)) has the same gridstate.size() == 0 lazy initialization guard as updateVisibility(). If the entity was moved to a larger grid without proper gridstate resize, the guard is skipped and the function proceeds to index into the undersized vector.

Root Cause

UIEntity.cpp:112-119:

// Lazy initialize gridstate if needed
if (self->data->gridstate.size() == 0) {
    self->data->gridstate.resize(self->data->grid->grid_w * self->data->grid->grid_h);
    for (auto& state : self->data->gridstate) {
        state.visible = false;
        state.discovered = false;
    }
}

Then at line 130:

obj->data = &(self->data->gridstate[y * self->data->grid->grid_w + x]);

If x and y are within the new grid's bounds but the gridstate vector is sized for the old grid, this index can be out of bounds.

Reproduction

import mcrfpy

small_grid = mcrfpy.Grid(grid_size=(10, 10))
large_grid = mcrfpy.Grid(grid_size=(50, 50))

entity = mcrfpy.Entity((5, 5), grid=small_grid)
entity.update_visibility()  # gridstate = 100

entity.grid = large_grid  # If gridstate not resized...

state = entity.at(30, 30)  # idx = 30*50+30 = 1530, but gridstate has 100 entries

Fix

Same defense-in-depth as #276 — validate gridstate size against current grid dimensions:

size_t expected = self->data->grid->grid_w * self->data->grid->grid_h;
if (self->data->gridstate.size() != expected) {
    self->data->gridstate.resize(expected);
    for (auto& state : self->data->gridstate) {
        state.visible = false;
        state.discovered = false;
    }
}

Severity

Medium — defense-in-depth. The primary fix is in the grid transfer methods (#258-#263), but this prevents crashes if those are bypassed.

  • #276 — Same guard in updateVisibility()
  • #264 — The dangling pointer returned by at() (separate issue)
## Summary `UIEntity::at()` (entity.at(x, y)) has the same `gridstate.size() == 0` lazy initialization guard as `updateVisibility()`. If the entity was moved to a larger grid without proper gridstate resize, the guard is skipped and the function proceeds to index into the undersized vector. ## Root Cause `UIEntity.cpp:112-119`: ```cpp // Lazy initialize gridstate if needed if (self->data->gridstate.size() == 0) { self->data->gridstate.resize(self->data->grid->grid_w * self->data->grid->grid_h); for (auto& state : self->data->gridstate) { state.visible = false; state.discovered = false; } } ``` Then at line 130: ```cpp obj->data = &(self->data->gridstate[y * self->data->grid->grid_w + x]); ``` If `x` and `y` are within the new grid's bounds but the gridstate vector is sized for the old grid, this index can be out of bounds. ## Reproduction ```python import mcrfpy small_grid = mcrfpy.Grid(grid_size=(10, 10)) large_grid = mcrfpy.Grid(grid_size=(50, 50)) entity = mcrfpy.Entity((5, 5), grid=small_grid) entity.update_visibility() # gridstate = 100 entity.grid = large_grid # If gridstate not resized... state = entity.at(30, 30) # idx = 30*50+30 = 1530, but gridstate has 100 entries ``` ## Fix Same defense-in-depth as #276 — validate gridstate size against current grid dimensions: ```cpp size_t expected = self->data->grid->grid_w * self->data->grid->grid_h; if (self->data->gridstate.size() != expected) { self->data->gridstate.resize(expected); for (auto& state : self->data->gridstate) { state.visible = false; state.discovered = false; } } ``` ## Severity **Medium** — defense-in-depth. The primary fix is in the grid transfer methods (#258-#263), but this prevents crashes if those are bypassed. ## Related - #276 — Same guard in updateVisibility() - #264 — The dangling pointer returned by at() (separate issue)
john closed this issue 2026-03-14 06:25:16 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
john/McRogueFace#278
No description provided.