From 362ea7b0f3bb858996198a8d760acbd3397dea22 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 28 Feb 2026 15:06:10 +0000 Subject: [PATCH] hyprctl: fix buffer overflowing writes to the socket --- hyprctl/src/main.cpp | 24 ++++++++++++------------ src/debug/HyprCtl.cpp | 36 +++++++++++++++++++++++++++++------- 2 files changed, 41 insertions(+), 19 deletions(-) diff --git a/hyprctl/src/main.cpp b/hyprctl/src/main.cpp index 7146c635..0a33f3ed 100644 --- a/hyprctl/src/main.cpp +++ b/hyprctl/src/main.cpp @@ -228,23 +228,23 @@ int request(std::string_view arg, int minArgs = 0, bool needRoll = false) { constexpr size_t BUFFER_SIZE = 8192; char buffer[BUFFER_SIZE] = {0}; - sizeWritten = read(SERVERSOCKET, buffer, BUFFER_SIZE); - - if (sizeWritten < 0) { - if (errno == EWOULDBLOCK) - log("Hyprland IPC didn't respond in time\n"); - log("Couldn't read (6)"); - return 6; - } - - reply += std::string(buffer, sizeWritten); - - while (sizeWritten == BUFFER_SIZE) { + // read all data until server closes the connection + // this handles partial writes on the server side under high load + while (true) { sizeWritten = read(SERVERSOCKET, buffer, BUFFER_SIZE); + if (sizeWritten < 0) { + if (errno == EWOULDBLOCK) + log("Hyprland IPC didn't respond in time\n"); log("Couldn't read (6)"); return 6; } + + if (sizeWritten == 0) { + // server closed connection, we're done + break; + } + reply += std::string(buffer, sizeWritten); } diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index f3a9402d..1fcb3dd1 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -2210,16 +2210,38 @@ std::string CHyprCtl::makeDynamicCall(const std::string& input) { } static bool successWrite(int fd, const std::string& data, bool needLog = true) { - if (write(fd, data.c_str(), data.length()) > 0) - return true; + size_t totalWritten = 0; + size_t remaining = data.length(); + size_t waitsDone = 0; + constexpr const size_t MAX_WAITS = 20; // 2000µs = 2ms - if (errno == EAGAIN) - return true; + while (totalWritten < data.length()) { + ssize_t written = write(fd, data.c_str() + totalWritten, remaining); - if (needLog) - Log::logger->log(Log::ERR, "Couldn't write to socket. Error: " + std::string(strerror(errno))); + if (waitsDone > MAX_WAITS) { + Log::logger->log(Log::ERR, "Couldn't write to socket. Buffer was full and the client couldn't read in time."); + return false; + } - return false; + if (written < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + // socket buffer full, wait a bit and retry + std::this_thread::sleep_for(std::chrono::microseconds(100)); + waitsDone++; + continue; + } + if (needLog) + Log::logger->log(Log::ERR, "Couldn't write to socket. Error: {}", strerror(errno)); + return false; + } + + waitsDone = 0; + + totalWritten += written; + remaining -= written; + } + + return true; } static void runWritingDebugLogThread(const int conn) {