changeset 15764:208bf8b36075 v8.1.0889

patch 8.1.0889: MS-Windows: a channel write may hang commit https://github.com/vim/vim/commit/6524068ff3252f1373807f1ebfde21408cef624e Author: Bram Moolenaar <Bram@vim.org> Date: Sun Feb 10 22:23:26 2019 +0100 patch 8.1.0889: MS-Windows: a channel write may hang Problem: MS-Windows: a channel write may hang. Solution: Check for WriteFile() not writing anything. (Yasuhiro Matsumoto, closes #3920)
author Bram Moolenaar <Bram@vim.org>
date Sun, 10 Feb 2019 22:30:07 +0100
parents 75ae11beca53
children e4f8d017a0c6
files src/channel.c src/testdir/test_channel.vim src/testdir/test_channel_pipe.py src/version.c
diffstat 4 files changed, 26 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/src/channel.c
+++ b/src/channel.c
@@ -91,9 +91,10 @@ fd_write(sock_T fd, char *buf, size_t le
 	    size = MAX_NAMED_PIPE_SIZE;
 	else
 	    size = (DWORD)todo;
-	// If the pipe overflows while the job does not read the data, WriteFile
-	// will block forever. This abandons the write.
+	// If the pipe overflows while the job does not read the data,
+	// WriteFile() will block forever. This abandons the write.
 	memset(&ov, 0, sizeof(ov));
+	nwrite = 0;
 	if (!WriteFile(h, buf + done, size, &nwrite, &ov))
 	{
 	    DWORD err = GetLastError();
@@ -104,6 +105,10 @@ fd_write(sock_T fd, char *buf, size_t le
 		return -1;
 	    FlushFileBuffers(h);
 	}
+	else if (nwrite == 0)
+	    // WriteFile() returns TRUE but did not write anything. This causes
+	    // a hang, so bail out.
+	    break;
 	todo -= nwrite;
 	done += nwrite;
     }
--- a/src/testdir/test_channel.vim
+++ b/src/testdir/test_channel.vim
@@ -2003,6 +2003,20 @@ func Test_raw_large_data()
   endtry
 endfunc
 
+func Test_no_hang_windows()
+  if !has('job') || !has('win32')
+    return
+  endif
+
+  try
+    let job = job_start(s:python . " test_channel_pipe.py busy",
+          \ {'mode': 'raw', 'drop': 'never', 'noblock': 0})
+    call assert_fails('call ch_sendraw(job, repeat("X", 80000))', 'E631:')
+  finally
+    call job_stop(job)
+  endtry
+endfunc
+
 func Test_job_exitval_and_termsig()
   if !has('unix')
     return
--- a/src/testdir/test_channel_pipe.py
+++ b/src/testdir/test_channel_pipe.py
@@ -18,6 +18,9 @@ if __name__ == "__main__":
             print(sys.argv[1], end='')
             sys.stdout.flush()
             sys.exit(0)
+        elif sys.argv[1].startswith("busy"):
+            time.sleep(100)
+            sys.exit(0)
         else:
             print(sys.argv[1])
             sys.stdout.flush()
--- 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 */
 /**/
+    889,
+/**/
     888,
 /**/
     887,