diff options
| author | Paul Eggert | 2026-04-12 22:56:16 -0700 |
|---|---|---|
| committer | Paul Eggert | 2026-04-12 23:21:02 -0700 |
| commit | 7d07690e5dade398da8a26805744f8bf1daafe8c (patch) | |
| tree | ef07c4b531d0654ae8bef142ba317fe0193f4be2 /lib-src | |
| parent | 46c08d85743e30cd024264703e4e1b6f8927fb58 (diff) | |
| download | emacs-7d07690e5dade398da8a26805744f8bf1daafe8c.tar.gz emacs-7d07690e5dade398da8a26805744f8bf1daafe8c.zip | |
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.
Diffstat (limited to 'lib-src')
| -rw-r--r-- | lib-src/emacsclient.c | 36 |
1 files 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) | |||
| 1975 | } | 1975 | } |
| 1976 | 1976 | ||
| 1977 | static bool | 1977 | static bool |
| 1978 | check_socket_timeout (int rl) | 1978 | check_socket_timeout (ssize_t rl) |
| 1979 | { | 1979 | { |
| 1980 | #ifndef WINDOWSNT | 1980 | #ifndef WINDOWSNT |
| 1981 | return (rl == -1) | 1981 | return (rl == -1) |
| @@ -1994,9 +1994,11 @@ main (int argc, char **argv) | |||
| 1994 | main_argv = argv; | 1994 | main_argv = argv; |
| 1995 | progname = argv[0] ? argv[0] : "emacsclient"; | 1995 | progname = argv[0] ? argv[0] : "emacsclient"; |
| 1996 | 1996 | ||
| 1997 | int rl = 0; | 1997 | ssize_t rl = 0; |
| 1998 | bool skiplf = true; | 1998 | bool skiplf = true; |
| 1999 | char string[BUFSIZ + 1]; | 1999 | char *recv_buf = NULL; |
| 2000 | ptrdiff_t recv_bufsize = 0; | ||
| 2001 | |||
| 2000 | int exit_status = EXIT_SUCCESS; | 2002 | int exit_status = EXIT_SUCCESS; |
| 2001 | 2003 | ||
| 2002 | #ifdef HAVE_NTGUI | 2004 | #ifdef HAVE_NTGUI |
| @@ -2208,6 +2210,8 @@ main (int argc, char **argv) | |||
| 2208 | 2210 | ||
| 2209 | set_socket_timeout (emacs_socket, timeout > 0 ? timeout : DEFAULT_TIMEOUT); | 2211 | set_socket_timeout (emacs_socket, timeout > 0 ? timeout : DEFAULT_TIMEOUT); |
| 2210 | bool saw_response = false; | 2212 | bool saw_response = false; |
| 2213 | ptrdiff_t nrecv = 0; | ||
| 2214 | |||
| 2211 | /* Now, wait for an answer and print any messages. */ | 2215 | /* Now, wait for an answer and print any messages. */ |
| 2212 | while (exit_status == EXIT_SUCCESS) | 2216 | while (exit_status == EXIT_SUCCESS) |
| 2213 | { | 2217 | { |
| @@ -2216,7 +2220,14 @@ main (int argc, char **argv) | |||
| 2216 | do | 2220 | do |
| 2217 | { | 2221 | { |
| 2218 | act_on_signals (emacs_socket); | 2222 | act_on_signals (emacs_socket); |
| 2219 | rl = recv (emacs_socket, string, BUFSIZ, 0); | 2223 | if (nrecv == recv_bufsize) |
| 2224 | { | ||
| 2225 | enum { DEFAULT_RECV_BUFSIZE = 4096 }; | ||
| 2226 | recv_bufsize = (recv_bufsize + (recv_bufsize >> 1) | ||
| 2227 | + DEFAULT_RECV_BUFSIZE); | ||
| 2228 | recv_buf = xrealloc (recv_buf, recv_bufsize); | ||
| 2229 | } | ||
| 2230 | rl = recv (emacs_socket, recv_buf + nrecv, recv_bufsize - nrecv, 0); | ||
| 2220 | retry = check_socket_timeout (rl); | 2231 | retry = check_socket_timeout (rl); |
| 2221 | if (retry && !saw_response) | 2232 | if (retry && !saw_response) |
| 2222 | { | 2233 | { |
| @@ -2239,16 +2250,17 @@ main (int argc, char **argv) | |||
| 2239 | if (rl <= 0) | 2250 | if (rl <= 0) |
| 2240 | break; | 2251 | break; |
| 2241 | 2252 | ||
| 2253 | nrecv += rl; | ||
| 2242 | saw_response = true; | 2254 | saw_response = true; |
| 2243 | string[rl] = '\0'; | ||
| 2244 | 2255 | ||
| 2245 | /* Loop over all NL-terminated messages. */ | 2256 | /* Loop over all NL-terminated messages. */ |
| 2246 | char *p = string; | 2257 | char *p = recv_buf; |
| 2247 | for (char *end_p = p; end_p && *end_p != '\0'; p = end_p) | 2258 | for (char *end_p = p; end_p < recv_buf + nrecv; p = end_p) |
| 2248 | { | 2259 | { |
| 2249 | end_p = strchr (p, '\n'); | 2260 | end_p = memchr (p, '\n', recv_buf + nrecv - p); |
| 2250 | if (end_p != NULL) | 2261 | if (!end_p) |
| 2251 | *end_p++ = '\0'; | 2262 | break; |
| 2263 | *end_p++ = '\0'; | ||
| 2252 | 2264 | ||
| 2253 | if (strprefix ("-emacs-pid ", p)) | 2265 | if (strprefix ("-emacs-pid ", p)) |
| 2254 | { | 2266 | { |
| @@ -2271,6 +2283,7 @@ main (int argc, char **argv) | |||
| 2271 | tty = true; | 2283 | tty = true; |
| 2272 | } | 2284 | } |
| 2273 | 2285 | ||
| 2286 | /* This discards any remaining data in recv_buf. */ | ||
| 2274 | goto retry; | 2287 | goto retry; |
| 2275 | } | 2288 | } |
| 2276 | else if (strprefix ("-print ", p)) | 2289 | else if (strprefix ("-print ", p)) |
| @@ -2324,6 +2337,9 @@ main (int argc, char **argv) | |||
| 2324 | skiplf = true; | 2337 | skiplf = true; |
| 2325 | } | 2338 | } |
| 2326 | } | 2339 | } |
| 2340 | |||
| 2341 | nrecv -= p - recv_buf; | ||
| 2342 | memmove (recv_buf, p, nrecv); | ||
| 2327 | } | 2343 | } |
| 2328 | 2344 | ||
| 2329 | if (!skiplf && 0 <= process_grouping ()) | 2345 | if (!skiplf && 0 <= process_grouping ()) |