From 6317022304a49c0033c52f0c6cdfe038e88dd314 Mon Sep 17 00:00:00 2001 From: Austin Horstman Date: Fri, 6 Mar 2026 18:33:19 -0600 Subject: [PATCH] fix(hyprland): guard malformed module events The language and submap modules assumed their Hyprland payload delimiters were always present. When that assumption is violated, the old code could perform invalid iterator math or throw while slicing the event string. Validate the expected separators up front and bail out with a warning when the event is malformed so the modules degrade safely instead of crashing the update path. Signed-off-by: Austin Horstman --- src/modules/hyprland/language.cpp | 26 +++++++++++++++++++++----- src/modules/hyprland/submap.cpp | 7 ++++++- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/modules/hyprland/language.cpp b/src/modules/hyprland/language.cpp index 25f6789d..6e0fe23d 100644 --- a/src/modules/hyprland/language.cpp +++ b/src/modules/hyprland/language.cpp @@ -63,19 +63,35 @@ auto Language::update() -> void { void Language::onEvent(const std::string& ev) { std::lock_guard lg(mutex_); - std::string kbName(begin(ev) + ev.find_last_of('>') + 1, begin(ev) + ev.find_first_of(',')); + const auto payloadStart = ev.find(">>"); + if (payloadStart == std::string::npos) { + spdlog::warn("hyprland language received malformed event: {}", ev); + return; + } + const auto payload = ev.substr(payloadStart + 2); + const auto kbSeparator = payload.find(','); + if (kbSeparator == std::string::npos) { + spdlog::warn("hyprland language received malformed event payload: {}", ev); + return; + } + std::string kbName = payload.substr(0, kbSeparator); // Last comma before variants parenthesis, eg: // activelayout>>micro-star-int'l-co.,-ltd.-msi-gk50-elite-gaming-keyboard,English (US, intl., // with dead keys) std::string beforeParenthesis; - auto parenthesisPos = ev.find_last_of('('); + auto parenthesisPos = payload.find_last_of('('); if (parenthesisPos == std::string::npos) { - beforeParenthesis = ev; + beforeParenthesis = payload; } else { - beforeParenthesis = std::string(begin(ev), begin(ev) + parenthesisPos); + beforeParenthesis = payload.substr(0, parenthesisPos); } - auto layoutName = ev.substr(beforeParenthesis.find_last_of(',') + 1); + const auto layoutSeparator = beforeParenthesis.find_last_of(','); + if (layoutSeparator == std::string::npos) { + spdlog::warn("hyprland language received malformed layout payload: {}", ev); + return; + } + auto layoutName = payload.substr(layoutSeparator + 1); if (config_.isMember("keyboard-name") && kbName != config_["keyboard-name"].asString()) return; // ignore diff --git a/src/modules/hyprland/submap.cpp b/src/modules/hyprland/submap.cpp index ff18e7f3..36b9bf79 100644 --- a/src/modules/hyprland/submap.cpp +++ b/src/modules/hyprland/submap.cpp @@ -75,7 +75,12 @@ void Submap::onEvent(const std::string& ev) { return; } - auto submapName = ev.substr(ev.find_first_of('>') + 2); + const auto separator = ev.find(">>"); + if (separator == std::string::npos) { + spdlog::warn("hyprland submap received malformed event: {}", ev); + return; + } + auto submapName = ev.substr(separator + 2); submap_ = submapName;