From 7d07690e5dade398da8a26805744f8bf1daafe8c Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sun, 12 Apr 2026 22:56:16 -0700 Subject: [PATCH] emacsclient receiving long-line fixes Do not mishandle long lines, or lines containing NUL, when receiving data. * lib-src/emacsclient.c (check_socket_timeout, main): Use ssize_t for return values from recv, since in theory the value could exceed INT_MAX now. (main): Do not use a fixed-size buffer for receiving data; instead, grow the buffer as needed (admittedly unlikely). When a partial line is received via recv, do not discard its data; instead, keep reading, possibly with a grown buffer. Do not ignore received data after a null byte is received. Add a comment about when received data is ignored due to a goto. --- lib-src/emacsclient.c | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/lib-src/emacsclient.c b/lib-src/emacsclient.c index 3ee4e3f92d5..134c2217650 100644 --- a/lib-src/emacsclient.c +++ b/lib-src/emacsclient.c @@ -1975,7 +1975,7 @@ set_socket_timeout (HSOCKET socket, int seconds) } static bool -check_socket_timeout (int rl) +check_socket_timeout (ssize_t rl) { #ifndef WINDOWSNT return (rl == -1) @@ -1994,9 +1994,11 @@ main (int argc, char **argv) main_argv = argv; progname = argv[0] ? argv[0] : "emacsclient"; - int rl = 0; + ssize_t rl = 0; bool skiplf = true; - char string[BUFSIZ + 1]; + char *recv_buf = NULL; + ptrdiff_t recv_bufsize = 0; + int exit_status = EXIT_SUCCESS; #ifdef HAVE_NTGUI @@ -2208,6 +2210,8 @@ main (int argc, char **argv) set_socket_timeout (emacs_socket, timeout > 0 ? timeout : DEFAULT_TIMEOUT); bool saw_response = false; + ptrdiff_t nrecv = 0; + /* Now, wait for an answer and print any messages. */ while (exit_status == EXIT_SUCCESS) { @@ -2216,7 +2220,14 @@ main (int argc, char **argv) do { act_on_signals (emacs_socket); - rl = recv (emacs_socket, string, BUFSIZ, 0); + if (nrecv == recv_bufsize) + { + enum { DEFAULT_RECV_BUFSIZE = 4096 }; + recv_bufsize = (recv_bufsize + (recv_bufsize >> 1) + + DEFAULT_RECV_BUFSIZE); + recv_buf = xrealloc (recv_buf, recv_bufsize); + } + rl = recv (emacs_socket, recv_buf + nrecv, recv_bufsize - nrecv, 0); retry = check_socket_timeout (rl); if (retry && !saw_response) { @@ -2239,16 +2250,17 @@ main (int argc, char **argv) if (rl <= 0) break; + nrecv += rl; saw_response = true; - string[rl] = '\0'; /* Loop over all NL-terminated messages. */ - char *p = string; - for (char *end_p = p; end_p && *end_p != '\0'; p = end_p) + char *p = recv_buf; + for (char *end_p = p; end_p < recv_buf + nrecv; p = end_p) { - end_p = strchr (p, '\n'); - if (end_p != NULL) - *end_p++ = '\0'; + end_p = memchr (p, '\n', recv_buf + nrecv - p); + if (!end_p) + break; + *end_p++ = '\0'; if (strprefix ("-emacs-pid ", p)) { @@ -2271,6 +2283,7 @@ main (int argc, char **argv) tty = true; } + /* This discards any remaining data in recv_buf. */ goto retry; } else if (strprefix ("-print ", p)) @@ -2324,6 +2337,9 @@ main (int argc, char **argv) skiplf = true; } } + + nrecv -= p - recv_buf; + memmove (recv_buf, p, nrecv); } if (!skiplf && 0 <= process_grouping ())