changeset 15766:9d18e8457209 v8.1.0890

patch 8.1.0890: pty allocation wrong if using file for out channel commit https://github.com/vim/vim/commit/593864817a08f9b719a093ef4fd8d4d35132ab86 Author: Bram Moolenaar <Bram@vim.org> Date: Sun Feb 10 22:43:46 2019 +0100 patch 8.1.0890: pty allocation wrong if using file for out channel Problem: Pty allocation wrong if using file for out channel and using null for in channel and null for error channel. Solution: Correct using use_file_for_out in condition. (Ozaki Kiichi, closes #3917)
author Bram Moolenaar <Bram@vim.org>
date Sun, 10 Feb 2019 22:45:06 +0100
parents e4f8d017a0c6
children 4ce2415e4034
files src/os_unix.c src/testdir/test_channel.vim src/version.c
diffstat 3 files changed, 74 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -4196,13 +4196,19 @@ set_default_child_environment(int is_ter
 /*
  * Open a PTY, with FD for the master and slave side.
  * When failing "pty_master_fd" and "pty_slave_fd" are -1.
- * When successful both file descriptors are stored.
+ * When successful both file descriptors are stored and the allocated pty name
+ * is stored in both "*name1" and "*name2".
  */
     static void
-open_pty(int *pty_master_fd, int *pty_slave_fd, char_u **namep)
+open_pty(int *pty_master_fd, int *pty_slave_fd, char_u **name1, char_u **name2)
 {
     char	*tty_name;
 
+    if (name1 != NULL)
+	*name1 = NULL;
+    if (name2 != NULL)
+	*name2 = NULL;
+
     *pty_master_fd = mch_openpty(&tty_name);	    // open pty
     if (*pty_master_fd >= 0)
     {
@@ -4219,8 +4225,13 @@ open_pty(int *pty_master_fd, int *pty_sl
 	    close(*pty_master_fd);
 	    *pty_master_fd = -1;
 	}
-	else if (namep != NULL)
-	    *namep = vim_strsave((char_u *)tty_name);
+	else
+	{
+	    if (name1 != NULL)
+		*name1 = vim_strsave((char_u *)tty_name);
+	    if (name2 != NULL)
+		*name2 = vim_strsave((char_u *)tty_name);
+	}
     }
 }
 #endif
@@ -4513,7 +4524,7 @@ mch_call_shell_fork(
 	 * If the slave can't be opened, close the master pty.
 	 */
 	if (p_guipty && !(options & (SHELL_READ|SHELL_WRITE)))
-	    open_pty(&pty_master_fd, &pty_slave_fd, NULL);
+	    open_pty(&pty_master_fd, &pty_slave_fd, NULL, NULL);
 	/*
 	 * If not opening a pty or it didn't work, try using pipes.
 	 */
@@ -5352,13 +5363,10 @@ mch_job_start(char **argv, job_T *job, j
 
     if (options->jo_pty
 	    && (!(use_file_for_in || use_null_for_in)
-		|| !(use_file_for_in || use_null_for_out)
+		|| !(use_file_for_out || use_null_for_out)
 		|| !(use_out_for_err || use_file_for_err || use_null_for_err)))
-    {
-	open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_out);
-	if (job->jv_tty_out != NULL)
-	    job->jv_tty_in = vim_strsave(job->jv_tty_out);
-    }
+	open_pty(&pty_master_fd, &pty_slave_fd,
+					    &job->jv_tty_out, &job->jv_tty_in);
 
     /* TODO: without the channel feature connect the child to /dev/null? */
     /* Open pipes for stdin, stdout, stderr. */
@@ -5834,9 +5842,7 @@ mch_create_pty_channel(job_T *job, jobop
     int		pty_slave_fd = -1;
     channel_T	*channel;
 
-    open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_out);
-    if (job->jv_tty_out != NULL)
-	job->jv_tty_in = vim_strsave(job->jv_tty_out);
+    open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_out, &job->jv_tty_in);
     close(pty_slave_fd);
 
     channel = add_channel();
--- a/src/testdir/test_channel.vim
+++ b/src/testdir/test_channel.vim
@@ -2040,3 +2040,55 @@ func Test_job_exitval_and_termsig()
   call assert_equal(-1, info.exitval)
   call assert_equal("term", info.termsig)
 endfunc
+
+func Test_job_tty_in_out()
+  if !has('job') || !has('unix')
+    return
+  endif
+
+  call writefile(['test'], 'Xtestin')
+  let in_opts = [{},
+        \ {'in_io': 'null'},
+        \ {'in_io': 'file', 'in_name': 'Xtestin'}]
+  let out_opts = [{},
+        \ {'out_io': 'null'},
+        \ {'out_io': 'file', 'out_name': 'Xtestout'}]
+  let err_opts = [{},
+        \ {'err_io': 'null'},
+        \ {'err_io': 'file', 'err_name': 'Xtesterr'},
+        \ {'err_io': 'out'}]
+  let opts = []
+
+  for in_opt in in_opts
+    let x = copy(in_opt)
+    for out_opt in out_opts
+      call extend(x, out_opt)
+      for err_opt in err_opts
+        call extend(x, err_opt)
+        let opts += [extend({'pty': 1}, x)]
+      endfor
+    endfor
+  endfor
+
+  for opt in opts
+    let job = job_start('echo', opt)
+    let info = job_info(job)
+    let msg = printf('option={"in_io": "%s", "out_io": "%s", "err_io": "%s"}',
+          \ get(opt, 'in_io', 'tty'),
+          \ get(opt, 'out_io', 'tty'),
+          \ get(opt, 'err_io', 'tty'))
+
+    if !has_key(opt, 'in_io') || !has_key(opt, 'out_io') || !has_key(opt, 'err_io')
+      call assert_notequal('', info.tty_in, msg)
+    else
+      call assert_equal('', info.tty_in, msg)
+    endif
+    call assert_equal(info.tty_in, info.tty_out, msg)
+
+    call WaitForAssert({-> assert_equal('dead', job_status(job))})
+  endfor
+
+  call delete('Xtestin')
+  call delete('Xtestout')
+  call delete('Xtesterr')
+endfunc
--- a/src/version.c
+++ b/src/version.c
@@ -784,6 +784,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    890,
+/**/
     889,
 /**/
     888,