diff --git a/src/channel.c b/src/channel.c index 34a1fc3e039e1..d728c77d9ffda 100644 --- a/src/channel.c +++ b/src/channel.c @@ -91,9 +91,10 @@ fd_write(sock_T fd, char *buf, size_t len) 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 len) 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; } diff --git a/src/testdir/test_channel.vim b/src/testdir/test_channel.vim index 2aef3e1dc4d82..becd5484f9157 100644 --- 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 diff --git a/src/testdir/test_channel_pipe.py b/src/testdir/test_channel_pipe.py index 810a8e3032869..5caffcbf9e345 100644 --- a/src/testdir/test_channel_pipe.py +++ b/src/testdir/test_channel_pipe.py @@ -18,6 +18,9 @@ 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() diff --git a/src/version.c b/src/version.c index e31b7cace66af..a990f2c3c1fc0 100644 --- a/src/version.c +++ b/src/version.c @@ -783,6 +783,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 889, /**/ 888, /**/