aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nvim/main.c4
-rw-r--r--src/nvim/os/fs.c23
-rw-r--r--test/functional/core/main_spec.lua48
-rw-r--r--test/unit/os/fs_spec.lua16
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'