summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVaxry <vaxry@vaxry.net>2026-02-28 15:06:10 +0000
committerVaxry <vaxry@vaxry.net>2026-02-28 15:06:10 +0000
commit362ea7b0f3bb858996198a8d760acbd3397dea22 (patch)
treed55c8f2ab7d368c3379a95b042e1fb0a81f5c961
parentf7114016c6dbf524763038642521892b473f4d36 (diff)
hyprctl: fix buffer overflowing writes to the socket
-rw-r--r--hyprctl/src/main.cpp24
-rw-r--r--src/debug/HyprCtl.cpp36
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;
+ }
+
+ 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 false;
+ return true;
}
static void runWritingDebugLogThread(const int conn) {