diff options
-rw-r--r-- | src/nvim/main.c | 4 | ||||
-rw-r--r-- | src/nvim/os/fs.c | 23 | ||||
-rw-r--r-- | test/functional/core/main_spec.lua | 48 | ||||
-rw-r--r-- | test/unit/os/fs_spec.lua | 16 |
4 files changed, 90 insertions, 1 deletions
diff --git a/src/nvim/main.c b/src/nvim/main.c index 99dd9fc18f..ce0426bd8e 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -1057,7 +1057,9 @@ scripterror: mch_exit(2); } if (STRCMP(argv[0], "-") == 0) { - scriptin[0] = stdin; + const int stdin_dup_fd = os_dup(STDIN_FILENO); + FILE *const stdin_dup = fdopen(stdin_dup_fd, "r"); + scriptin[0] = stdin_dup; } else if ((scriptin[0] = mch_fopen(argv[0], READBIN)) == NULL) { mch_errmsg(_("Cannot open for reading: \"")); mch_errmsg(argv[0]); diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index 2beeae7ec6..9ce50d4afd 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -430,6 +430,29 @@ int os_close(const int fd) return r; } +/// Duplicate file descriptor +/// +/// @param[in] fd File descriptor to duplicate. +/// +/// @return New file descriptor or libuv error code (< 0). +int os_dup(const int fd) + FUNC_ATTR_WARN_UNUSED_RESULT +{ + int ret; +os_dup_dup: + ret = dup(fd); + if (ret < 0) { + const int error = os_translate_sys_error(errno); + errno = 0; + if (error == UV_EINTR) { + goto os_dup_dup; + } else { + return error; + } + } + return ret; +} + /// Read from a file /// /// Handles EINTR and ENOMEM, but not other errors. diff --git a/test/functional/core/main_spec.lua b/test/functional/core/main_spec.lua index c3aeb30398..bad5d72142 100644 --- a/test/functional/core/main_spec.lua +++ b/test/functional/core/main_spec.lua @@ -1,7 +1,9 @@ local lfs = require('lfs') local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') local eq = helpers.eq +local feed = helpers.feed local clear = helpers.clear local funcs = helpers.funcs local nvim_prog = helpers.nvim_prog @@ -53,5 +55,51 @@ describe('Command-line option', function() local attrs = lfs.attributes(fname) eq(#('100500\n'), attrs.size) end) + it('does not crash after reading from stdin in non-headless mode', function() + local screen = Screen.new(40, 8) + screen:attach() + eq(nil, lfs.attributes(fname)) + funcs.termopen({ + nvim_prog_abs(), '-u', 'NONE', '-i', 'NONE', + '--cmd', 'set noswapfile shortmess+=IFW fileformats=unix', + '-s', '-' + }) + screen:expect([[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:[No Name] 0,0-1 All}| + | + | + ]], { + [1] = {foreground = 4210943, special = Screen.colors.Grey0}, + [2] = {special = Screen.colors.Grey0, bold = true, reverse = true} + }) + feed('i:cq<CR><C-\\><C-n>') + screen:expect([[ + ^ | + [Process exited 1] | + | + | + | + | + | + | + ]]) + --[=[ Example of incorrect output: + screen:expect([[ + ^nvim: /var/tmp/portage/dev-libs/libuv-1.| + 10.2/work/libuv-1.10.2/src/unix/core.c:5| + 19: uv__close: Assertion `fd > STDERR_FI| + LENO' failed. | + | + [Process exited 6] | + | + | + ]]) + ]=] + end) end) end) diff --git a/test/unit/os/fs_spec.lua b/test/unit/os/fs_spec.lua index 860ebfdbcb..b03040260f 100644 --- a/test/unit/os/fs_spec.lua +++ b/test/unit/os/fs_spec.lua @@ -483,6 +483,22 @@ describe('fs function', function() end) end) + describe('os_dup', function() + itp('returns new file descriptor', function() + local dup0 = fs.os_dup(0) + local dup1 = fs.os_dup(1) + local dup2 = fs.os_dup(2) + local tbl = {[0]=true, [1]=true, [2]=true, + [tonumber(dup0)]=true, [tonumber(dup1)]=true, + [tonumber(dup2)]=true} + local i = 0 + for _, _ in pairs(tbl) do + i = i + 1 + end + eq(i, 6) -- All fds must be unique + end) + end) + describe('os_open', function() local new_file = 'test_new_file' local existing_file = 'unit-test-directory/test_existing.file' |