🔍 Module Scanned
modules/engine-input/src/ (automated audit scan)
📝 Summary
When keys_pressed.put() fails due to allocation error, a key is added to keys_down but not keys_pressed, creating an inconsistent state where isKeyDown returns true but isKeyPressed returns false for the same key. This breaks the InputMapper's isActionActive logic which checks both held and pressed states.
📍 Location
- File:
modules/engine-input/src/input.zig:100-104
- Function/Scope:
processEvent / SDL_EVENT_KEY_DOWN handling
🔴 Severity: Medium
- Medium: Missing error handling leading to state inconsistency in edge case
💥 Impact
If keys_pressed.put() fails (e.g., OOM), a key appears held (isKeyDown=true) but never registered as pressed (isKeyPressed=false). This breaks InputMapper.isActionActive checks that rely on isKeyPressed, causing held keys to fail action triggers that depend on press detection. The key also becomes "stuck" in keys_down since the next release event will attempt to remove it again.
🔎 Evidence
c.SDL_EVENT_KEY_DOWN => {
if (!event.key.repeat) {
const key = Key.fromSDL(event.key.key);
self.keys_down.put(key, {}) catch {}; // Line 102 - succeeds
self.keys_pressed.put(key, {}) catch {}; // Line 103 - FAILS, key not in keys_pressed
}
},
If line 103's put fails, the key is in keys_down (line 102 succeeded) but NOT in keys_pressed. Result: isKeyDown=true, isKeyPressed=false for the same key — inconsistent.
The same pattern exists for release (lines 106-109):
c.SDL_EVENT_KEY_UP => {
const key = Key.fromSDL(event.key.key);
_ = self.keys_down.remove(key); // Line 108 - succeeds
self.keys_released.put(key, {}) catch {}; // Line 109 - FAILS, key not in keys_released
},
🛠️ Proposed Fix
When keys_pressed.put() fails, remove the key from keys_down to maintain consistency:
c.SDL_EVENT_KEY_DOWN => {
if (!event.key.repeat) {
const key = Key.fromSDL(event.key.key);
self.keys_down.put(key, {}) catch {};
if (self.keys_pressed.put(key, {}) catch {}) |_| {
_ = self.keys_down.remove(key); // Roll back keys_down on keys_pressed failure
}
}
},
Alternatively, propagate the error and let the caller decide whether to crash or roll back.
✅ Acceptance Criteria
📚 References
🔍 Module Scanned
modules/engine-input/src/(automated audit scan)📝 Summary
When
keys_pressed.put()fails due to allocation error, a key is added tokeys_downbut notkeys_pressed, creating an inconsistent state whereisKeyDownreturnstruebutisKeyPressedreturnsfalsefor the same key. This breaks the InputMapper'sisActionActivelogic which checks both held and pressed states.📍 Location
modules/engine-input/src/input.zig:100-104processEvent/SDL_EVENT_KEY_DOWNhandling🔴 Severity: Medium
💥 Impact
If
keys_pressed.put()fails (e.g., OOM), a key appears held (isKeyDown=true) but never registered as pressed (isKeyPressed=false). This breaksInputMapper.isActionActivechecks that rely onisKeyPressed, causing held keys to fail action triggers that depend on press detection. The key also becomes "stuck" inkeys_downsince the next release event will attempt to remove it again.🔎 Evidence
If line 103's
putfails, the key is inkeys_down(line 102 succeeded) but NOT inkeys_pressed. Result:isKeyDown=true,isKeyPressed=false for the same key — inconsistent.The same pattern exists for release (lines 106-109):
🛠️ Proposed Fix
When
keys_pressed.put()fails, remove the key fromkeys_downto maintain consistency:Alternatively, propagate the error and let the caller decide whether to crash or roll back.
✅ Acceptance Criteria
isKeyDownandisKeyPressedreturn consistent results for the same key (both true when key is both held AND was pressed this frame)keys_downafter failed press registrationzig build testpasses📚 References
catch {}error handling pattern)