diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/ex_getln.c | 3 | ||||
-rw-r--r-- | src/nvim/fileio.c | 4 | ||||
-rw-r--r-- | src/nvim/memline.c | 12 | ||||
-rw-r--r-- | src/nvim/os/pty_process.c | 89 | ||||
-rw-r--r-- | src/nvim/vim.h | 7 |
5 files changed, 94 insertions, 21 deletions
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index d5f7a218f4..238beebf3e 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -10,6 +10,7 @@ * ex_getln.c: Functions for entering and editing an Ex command line. */ +#include <assert.h> #include <errno.h> #include <stdbool.h> #include <string.h> @@ -3858,8 +3859,10 @@ expand_shellcmd ( STRLCPY(buf + l, pat, MAXPATHL - l); /* Expand matches in one directory of $PATH. */ + char_u **prev_file = *file; ret = expand_wildcards(1, &buf, num_file, file, flags); if (ret == OK) { + assert(*file != prev_file); ga_grow(&ga, *num_file); { for (i = 0; i < *num_file; ++i) { diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 9d4c990f3a..799a6a2a50 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -7416,7 +7416,7 @@ long read_eintr(int fd, void *buf, size_t bufsize) long ret; for (;; ) { - ret = vim_read(fd, buf, bufsize); + ret = read(fd, buf, bufsize); if (ret >= 0 || errno != EINTR) break; } @@ -7435,7 +7435,7 @@ long write_eintr(int fd, void *buf, size_t bufsize) /* Repeat the write() so long it didn't fail, other than being interrupted * by a signal. */ while (ret < (long)bufsize) { - wlen = vim_write(fd, (char *)buf + ret, bufsize - ret); + wlen = write(fd, (char *)buf + ret, bufsize - ret); if (wlen < 0) { if (errno != EINTR) break; diff --git a/src/nvim/memline.c b/src/nvim/memline.c index 5a577c6378..d6d7d3db1a 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -54,6 +54,7 @@ #include "nvim/cursor.h" #include "nvim/eval.h" #include "nvim/fileio.h" +#include "nvim/func_attr.h" #include "nvim/main.h" #include "nvim/mark.h" #include "nvim/mbyte.h" @@ -630,6 +631,15 @@ static int ml_check_b0_id(ZERO_BL *b0p) return OK; } +/// Return true if all strings in b0 are correct (nul-terminated). +static bool ml_check_b0_strings(ZERO_BL *b0p) FUNC_ATTR_NONNULL_ALL +{ + return (memchr(b0p->b0_version, NUL, 10) + && memchr(b0p->b0_uname, NUL, B0_UNAME_SIZE) + && memchr(b0p->b0_hname, NUL, B0_HNAME_SIZE) + && memchr(b0p->b0_fname, NUL, B0_FNAME_SIZE_CRYPT)); +} + /* * Update the timestamp or the B0_SAME_DIR flag of the .swp file. */ @@ -1522,6 +1532,8 @@ static time_t swapfile_info(char_u *fname) MSG_PUTS(_(" [from Vim version 3.0]")); } else if (ml_check_b0_id(&b0) == FAIL) { MSG_PUTS(_(" [does not look like a Vim swap file]")); + } else if (!ml_check_b0_strings(&b0)) { + MSG_PUTS(_(" [garbled strings (not nul terminated)]")); } else { MSG_PUTS(_(" file name: ")); if (b0.b0_fname[0] == NUL) diff --git a/src/nvim/os/pty_process.c b/src/nvim/os/pty_process.c index bd7247c741..c135efc6d3 100644 --- a/src/nvim/os/pty_process.c +++ b/src/nvim/os/pty_process.c @@ -20,6 +20,7 @@ #include <uv.h> +#include "nvim/func_attr.h" #include "nvim/os/job.h" #include "nvim/os/job_defs.h" #include "nvim/os/job_private.h" @@ -37,9 +38,10 @@ typedef struct { int tty_fd; } PtyProcess; -void pty_process_init(Job *job) +void pty_process_init(Job *job) FUNC_ATTR_NONNULL_ALL { PtyProcess *ptyproc = xmalloc(sizeof(PtyProcess)); + ptyproc->tty_fd = -1; if (job->opts.writable) { uv_pipe_init(uv_default_loop(), &ptyproc->proc_stdin, 0); @@ -62,14 +64,35 @@ void pty_process_init(Job *job) job->process = ptyproc; } -void pty_process_destroy(Job *job) +void pty_process_destroy(Job *job) FUNC_ATTR_NONNULL_ALL { free(job->opts.term_name); free(job->process); job->process = NULL; } -bool pty_process_spawn(Job *job) +static bool set_pipe_duplicating_descriptor(int fd, uv_pipe_t *pipe) + FUNC_ATTR_NONNULL_ALL +{ + int fd_dup = dup(fd); + if (fd_dup < 0) { + ELOG("Failed to dup descriptor %d: %s", fd, strerror(errno)); + return false; + } + int uv_result = uv_pipe_open(pipe, fd_dup); + if (uv_result) { + ELOG("Failed to set pipe to descriptor %d: %s", + fd_dup, uv_strerror(uv_result)); + close(fd_dup); + return false; + } + return true; +} + +static const unsigned int KILL_RETRIES = 5; +static const unsigned int KILL_TIMEOUT = 2; // seconds + +bool pty_process_spawn(Job *job) FUNC_ATTR_NONNULL_ALL { int master; PtyProcess *ptyproc = job->process; @@ -88,18 +111,29 @@ bool pty_process_spawn(Job *job) } // make sure the master file descriptor is non blocking - fcntl(master, F_SETFL, fcntl(master, F_GETFL) | O_NONBLOCK); + int master_status_flags = fcntl(master, F_GETFL); + if (master_status_flags == -1) { + ELOG("Failed to get master descriptor status flags: %s", strerror(errno)); + goto error; + } + if (fcntl(master, F_SETFL, master_status_flags | O_NONBLOCK) == -1) { + ELOG("Failed to make master descriptor non-blocking: %s", strerror(errno)); + goto error; + } - if (job->opts.writable) { - uv_pipe_open(&ptyproc->proc_stdin, dup(master)); + if (job->opts.writable + && !set_pipe_duplicating_descriptor(master, &ptyproc->proc_stdin)) { + goto error; } - if (job->opts.stdout_cb) { - uv_pipe_open(&ptyproc->proc_stdout, dup(master)); + if (job->opts.stdout_cb + && !set_pipe_duplicating_descriptor(master, &ptyproc->proc_stdout)) { + goto error; } - if (job->opts.stderr_cb) { - uv_pipe_open(&ptyproc->proc_stderr, dup(master)); + if (job->opts.stderr_cb + && !set_pipe_duplicating_descriptor(master, &ptyproc->proc_stderr)) { + goto error; } uv_signal_init(uv_default_loop(), &ptyproc->schld); @@ -108,25 +142,52 @@ bool pty_process_spawn(Job *job) ptyproc->tty_fd = master; job->pid = pid; return true; + +error: + close(master); + + // terminate spawned process + kill(pid, SIGTERM); + int status, child; + unsigned int try = 0; + while (try++ < KILL_RETRIES && !(child = waitpid(pid, &status, WNOHANG))) { + sleep(KILL_TIMEOUT); + } + if (child != pid) { + kill(pid, SIGKILL); + } + + return false; } -void pty_process_close(Job *job) +void pty_process_close(Job *job) FUNC_ATTR_NONNULL_ALL { PtyProcess *ptyproc = job->process; uv_signal_stop(&ptyproc->schld); uv_close((uv_handle_t *)&ptyproc->schld, NULL); + pty_process_close_master(job); job_close_streams(job); job_decref(job); } +void pty_process_close_master(Job *job) FUNC_ATTR_NONNULL_ALL +{ + PtyProcess *ptyproc = job->process; + if (ptyproc->tty_fd >= 0) { + close(ptyproc->tty_fd); + ptyproc->tty_fd = -1; + } +} + void pty_process_resize(Job *job, uint16_t width, uint16_t height) + FUNC_ATTR_NONNULL_ALL { PtyProcess *ptyproc = job->process; ptyproc->winsize = (struct winsize){height, width, 0, 0}; ioctl(ptyproc->tty_fd, TIOCSWINSZ, &ptyproc->winsize); } -static void init_child(Job *job) +static void init_child(Job *job) FUNC_ATTR_NONNULL_ALL { unsetenv("COLUMNS"); unsetenv("LINES"); @@ -146,7 +207,7 @@ static void init_child(Job *job) fprintf(stderr, "execvp failed: %s\n", strerror(errno)); } -static void chld_handler(uv_signal_t *handle, int signum) +static void chld_handler(uv_signal_t *handle, int signum) FUNC_ATTR_NONNULL_ALL { Job *job = handle->data; int stat = 0; @@ -171,7 +232,7 @@ static void chld_handler(uv_signal_t *handle, int signum) pty_process_close(job); } -static void init_termios(struct termios *termios) +static void init_termios(struct termios *termios) FUNC_ATTR_NONNULL_ALL { memset(termios, 0, sizeof(struct termios)); // Taken from pangoterm diff --git a/src/nvim/vim.h b/src/nvim/vim.h index 29d61dcbde..410c2602c8 100644 --- a/src/nvim/vim.h +++ b/src/nvim/vim.h @@ -322,13 +322,10 @@ enum { (size_t)(n)) #ifndef EINTR -# define read_eintr(fd, buf, count) vim_read((fd), (buf), (count)) -# define write_eintr(fd, buf, count) vim_write((fd), (buf), (count)) +# define read_eintr(fd, buf, count) read((fd), (buf), (count)) +# define write_eintr(fd, buf, count) write((fd), (buf), (count)) #endif -# define vim_read(fd, buf, count) read((fd), (char *)(buf), (size_t) (count)) -# define vim_write(fd, buf, count) write((fd), (char *)(buf), (size_t) (count)) - /* * Enums need a typecast to be used as array index (for Ultrix). */ |