Skip to content

Commit 772153f

Browse files
committed
patch 8.1.0993: ch_read() may return garbage if terminating NL is missing
Problem: ch_read() may return garbage if terminating NL is missing. Solution: Add terminating NUL. (Ozaki Kiichi, closes #4065)
1 parent cce713d commit 772153f

3 files changed

Lines changed: 42 additions & 35 deletions

File tree

src/channel.c

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1797,6 +1797,7 @@ channel_consume(channel_T *channel, ch_part_T part, int len)
17971797

17981798
mch_memmove(buf, buf + len, node->rq_buflen - len);
17991799
node->rq_buflen -= len;
1800+
node->rq_buffer[node->rq_buflen] = NUL;
18001801
}
18011802

18021803
/*
@@ -1819,7 +1820,7 @@ channel_collapse(channel_T *channel, ch_part_T part, int want_nl)
18191820
return FAIL;
18201821

18211822
last_node = node->rq_next;
1822-
len = node->rq_buflen + last_node->rq_buflen + 1;
1823+
len = node->rq_buflen + last_node->rq_buflen;
18231824
if (want_nl)
18241825
while (last_node->rq_next != NULL
18251826
&& channel_first_nl(last_node) == NULL)
@@ -1828,7 +1829,7 @@ channel_collapse(channel_T *channel, ch_part_T part, int want_nl)
18281829
len += last_node->rq_buflen;
18291830
}
18301831

1831-
p = newbuf = alloc(len);
1832+
p = newbuf = alloc(len + 1);
18321833
if (newbuf == NULL)
18331834
return FAIL; /* out of memory */
18341835
mch_memmove(p, node->rq_buffer, node->rq_buflen);
@@ -1842,6 +1843,7 @@ channel_collapse(channel_T *channel, ch_part_T part, int want_nl)
18421843
p += n->rq_buflen;
18431844
vim_free(n->rq_buffer);
18441845
}
1846+
*p = NUL;
18451847
node->rq_buflen = (long_u)(p - newbuf);
18461848

18471849
/* dispose of the collapsed nodes and their buffers */
@@ -2666,30 +2668,20 @@ may_invoke_callback(channel_T *channel, ch_part_T part)
26662668
}
26672669
buf = node->rq_buffer;
26682670

2669-
if (nl == NULL)
2670-
{
2671-
/* Flush remaining message that is missing a NL. */
2672-
char_u *new_buf;
2673-
2674-
new_buf = vim_realloc(buf, node->rq_buflen + 1);
2675-
if (new_buf == NULL)
2676-
/* This might fail over and over again, should the message
2677-
* be dropped? */
2678-
return FALSE;
2679-
buf = new_buf;
2680-
node->rq_buffer = buf;
2681-
nl = buf + node->rq_buflen++;
2682-
*nl = NUL;
2683-
}
2684-
2685-
/* Convert NUL to NL, the internal representation. */
2686-
for (p = buf; p < nl && p < buf + node->rq_buflen; ++p)
2671+
// Convert NUL to NL, the internal representation.
2672+
for (p = buf; (nl == NULL || p < nl)
2673+
&& p < buf + node->rq_buflen; ++p)
26872674
if (*p == NUL)
26882675
*p = NL;
26892676

2690-
if (nl + 1 == buf + node->rq_buflen)
2677+
if (nl == NULL)
2678+
{
2679+
// get the whole buffer, drop the NL
2680+
msg = channel_get(channel, part, NULL);
2681+
}
2682+
else if (nl + 1 == buf + node->rq_buflen)
26912683
{
2692-
/* get the whole buffer, drop the NL */
2684+
// get the whole buffer
26932685
msg = channel_get(channel, part, NULL);
26942686
*nl = NUL;
26952687
}

src/testdir/test_channel.vim

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -203,8 +203,7 @@ func Ch_communicate(port)
203203
let start = reltime()
204204
call assert_equal(v:none, ch_read(handle, {'timeout': 333}))
205205
let elapsed = reltime(start)
206-
call assert_true(reltimefloat(elapsed) > 0.3)
207-
call assert_true(reltimefloat(elapsed) < 0.6)
206+
call assert_inrange(0.3, 0.6, reltimefloat(reltime(start)))
208207

209208
" Send without waiting for a response, then wait for a response.
210209
call ch_sendexpr(handle, 'wait a bit')
@@ -434,9 +433,7 @@ func Test_connect_waittime()
434433
else
435434
" Failed connection should wait about 500 msec. Can be longer if the
436435
" computer is busy with other things.
437-
let elapsed = reltime(start)
438-
call assert_true(reltimefloat(elapsed) > 0.3)
439-
call assert_true(reltimefloat(elapsed) < 1.5)
436+
call assert_inrange(0.3, 1.5, reltimefloat(reltime(start)))
440437
endif
441438
catch
442439
if v:exception !~ 'Connection reset by peer'
@@ -1590,8 +1587,7 @@ func Test_exit_callback_interval()
15901587
else
15911588
let elapsed = 1.0
15921589
endif
1593-
call assert_true(elapsed > 0.5)
1594-
call assert_true(elapsed < 1.0)
1590+
call assert_inrange(0.5, 1.0, elapsed)
15951591
endfunc
15961592

15971593
"""""""""
@@ -1764,19 +1760,35 @@ func Test_raw_passes_nul()
17641760
bwipe!
17651761
endfunc
17661762

1767-
func MyLineCountCb(ch, msg)
1768-
let g:linecount += 1
1769-
endfunc
1770-
17711763
func Test_read_nonl_line()
17721764
if !has('job')
17731765
return
17741766
endif
17751767

17761768
let g:linecount = 0
17771769
let arg = 'import sys;sys.stdout.write("1\n2\n3")'
1778-
call job_start([s:python, '-c', arg], {'callback': 'MyLineCountCb'})
1770+
call job_start([s:python, '-c', arg], {'callback': {-> execute('let g:linecount += 1')}})
17791771
call WaitForAssert({-> assert_equal(3, g:linecount)})
1772+
unlet g:linecount
1773+
endfunc
1774+
1775+
func Test_read_nonl_in_close_cb()
1776+
if !has('job')
1777+
return
1778+
endif
1779+
1780+
func s:close_cb(ch)
1781+
while ch_status(a:ch) == 'buffered'
1782+
let g:out .= ch_read(a:ch)
1783+
endwhile
1784+
endfunc
1785+
1786+
let g:out = ''
1787+
let arg = 'import sys;sys.stdout.write("1\n2\n3")'
1788+
call job_start([s:python, '-c', arg], {'close_cb': function('s:close_cb')})
1789+
call WaitForAssert({-> assert_equal('123', g:out)})
1790+
unlet g:out
1791+
delfunc s:close_cb
17801792
endfunc
17811793

17821794
func Test_read_from_terminated_job()
@@ -1786,8 +1798,9 @@ func Test_read_from_terminated_job()
17861798

17871799
let g:linecount = 0
17881800
let arg = 'import os,sys;os.close(1);sys.stderr.write("test\n")'
1789-
call job_start([s:python, '-c', arg], {'callback': 'MyLineCountCb'})
1801+
call job_start([s:python, '-c', arg], {'callback': {-> execute('let g:linecount += 1')}})
17901802
call WaitForAssert({-> assert_equal(1, g:linecount)})
1803+
unlet g:linecount
17911804
endfunc
17921805

17931806
func Test_job_start_windows()

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -779,6 +779,8 @@ static char *(features[]) =
779779

780780
static int included_patches[] =
781781
{ /* Add new patch number below this line */
782+
/**/
783+
993,
782784
/**/
783785
992,
784786
/**/

0 commit comments

Comments
 (0)