Patch 8.1.0993
Problem:    ch_read() may return garbage if terminating NL is missing.
Solution:   Add terminating NUL. (Ozaki Kiichi, closes #4065)
Files:      src/channel.c, src/testdir/test_channel.vim


*** ../vim-8.1.0992/src/channel.c       2019-02-20 22:45:01.723613804 +0100
--- src/channel.c       2019-03-04 12:04:42.771564943 +0100
***************
*** 1797,1802 ****
--- 1797,1803 ----
  
      mch_memmove(buf, buf + len, node->rq_buflen - len);
      node->rq_buflen -= len;
+     node->rq_buffer[node->rq_buflen] = NUL;
  }
  
  /*
***************
*** 1819,1825 ****
        return FAIL;
  
      last_node = node->rq_next;
!     len = node->rq_buflen + last_node->rq_buflen + 1;
      if (want_nl)
        while (last_node->rq_next != NULL
                && channel_first_nl(last_node) == NULL)
--- 1820,1826 ----
        return FAIL;
  
      last_node = node->rq_next;
!     len = node->rq_buflen + last_node->rq_buflen;
      if (want_nl)
        while (last_node->rq_next != NULL
                && channel_first_nl(last_node) == NULL)
***************
*** 1828,1834 ****
            len += last_node->rq_buflen;
        }
  
!     p = newbuf = alloc(len);
      if (newbuf == NULL)
        return FAIL;        /* out of memory */
      mch_memmove(p, node->rq_buffer, node->rq_buflen);
--- 1829,1835 ----
            len += last_node->rq_buflen;
        }
  
!     p = newbuf = alloc(len + 1);
      if (newbuf == NULL)
        return FAIL;        /* out of memory */
      mch_memmove(p, node->rq_buffer, node->rq_buflen);
***************
*** 1842,1847 ****
--- 1843,1849 ----
        p += n->rq_buflen;
        vim_free(n->rq_buffer);
      }
+     *p = NUL;
      node->rq_buflen = (long_u)(p - newbuf);
  
      /* dispose of the collapsed nodes and their buffers */
***************
*** 2666,2695 ****
            }
            buf = node->rq_buffer;
  
!           if (nl == NULL)
!           {
!               /* Flush remaining message that is missing a NL. */
!               char_u  *new_buf;
! 
!               new_buf = vim_realloc(buf, node->rq_buflen + 1);
!               if (new_buf == NULL)
!                   /* This might fail over and over again, should the message
!                    * be dropped? */
!                   return FALSE;
!               buf = new_buf;
!               node->rq_buffer = buf;
!               nl = buf + node->rq_buflen++;
!               *nl = NUL;
!           }
! 
!           /* Convert NUL to NL, the internal representation. */
!           for (p = buf; p < nl && p < buf + node->rq_buflen; ++p)
                if (*p == NUL)
                    *p = NL;
  
!           if (nl + 1 == buf + node->rq_buflen)
            {
!               /* get the whole buffer, drop the NL */
                msg = channel_get(channel, part, NULL);
                *nl = NUL;
            }
--- 2668,2687 ----
            }
            buf = node->rq_buffer;
  
!           // Convert NUL to NL, the internal representation.
!           for (p = buf; (nl == NULL || p < nl)
!                                           && p < buf + node->rq_buflen; ++p)
                if (*p == NUL)
                    *p = NL;
  
!           if (nl == NULL)
!           {
!               // get the whole buffer, drop the NL
!               msg = channel_get(channel, part, NULL);
!           }
!           else if (nl + 1 == buf + node->rq_buflen)
            {
!               // get the whole buffer
                msg = channel_get(channel, part, NULL);
                *nl = NUL;
            }
*** ../vim-8.1.0992/src/testdir/test_channel.vim        2019-02-11 
22:00:07.671917613 +0100
--- src/testdir/test_channel.vim        2019-03-04 12:01:07.813113919 +0100
***************
*** 203,210 ****
    let start = reltime()
    call assert_equal(v:none, ch_read(handle, {'timeout': 333}))
    let elapsed = reltime(start)
!   call assert_true(reltimefloat(elapsed) > 0.3)
!   call assert_true(reltimefloat(elapsed) < 0.6)
  
    " Send without waiting for a response, then wait for a response.
    call ch_sendexpr(handle, 'wait a bit')
--- 203,209 ----
    let start = reltime()
    call assert_equal(v:none, ch_read(handle, {'timeout': 333}))
    let elapsed = reltime(start)
!   call assert_inrange(0.3, 0.6, reltimefloat(reltime(start)))
  
    " Send without waiting for a response, then wait for a response.
    call ch_sendexpr(handle, 'wait a bit')
***************
*** 434,442 ****
      else
        " Failed connection should wait about 500 msec.  Can be longer if the
        " computer is busy with other things.
!       let elapsed = reltime(start)
!       call assert_true(reltimefloat(elapsed) > 0.3)
!       call assert_true(reltimefloat(elapsed) < 1.5)
      endif
    catch
      if v:exception !~ 'Connection reset by peer'
--- 433,439 ----
      else
        " Failed connection should wait about 500 msec.  Can be longer if the
        " computer is busy with other things.
!       call assert_inrange(0.3, 1.5, reltimefloat(reltime(start)))
      endif
    catch
      if v:exception !~ 'Connection reset by peer'
***************
*** 1590,1597 ****
    else
      let elapsed = 1.0
    endif
!   call assert_true(elapsed > 0.5)
!   call assert_true(elapsed < 1.0)
  endfunc
  
  """""""""
--- 1587,1593 ----
    else
      let elapsed = 1.0
    endif
!   call assert_inrange(0.5, 1.0, elapsed)
  endfunc
  
  """""""""
***************
*** 1764,1773 ****
    bwipe!
  endfunc
  
- func MyLineCountCb(ch, msg)
-   let g:linecount += 1
- endfunc
- 
  func Test_read_nonl_line()
    if !has('job')
      return
--- 1760,1765 ----
***************
*** 1775,1782 ****
  
    let g:linecount = 0
    let arg = 'import sys;sys.stdout.write("1\n2\n3")'
!   call job_start([s:python, '-c', arg], {'callback': 'MyLineCountCb'})
    call WaitForAssert({-> assert_equal(3, g:linecount)})
  endfunc
  
  func Test_read_from_terminated_job()
--- 1767,1794 ----
  
    let g:linecount = 0
    let arg = 'import sys;sys.stdout.write("1\n2\n3")'
!   call job_start([s:python, '-c', arg], {'callback': {-> execute('let 
g:linecount += 1')}})
    call WaitForAssert({-> assert_equal(3, g:linecount)})
+   unlet g:linecount
+ endfunc
+ 
+ func Test_read_nonl_in_close_cb()
+   if !has('job')
+     return
+   endif
+ 
+   func s:close_cb(ch)
+     while ch_status(a:ch) == 'buffered'
+       let g:out .= ch_read(a:ch)
+     endwhile
+   endfunc
+ 
+   let g:out = ''
+   let arg = 'import sys;sys.stdout.write("1\n2\n3")'
+   call job_start([s:python, '-c', arg], {'close_cb': function('s:close_cb')})
+   call WaitForAssert({-> assert_equal('123', g:out)})
+   unlet g:out
+   delfunc s:close_cb
  endfunc
  
  func Test_read_from_terminated_job()
***************
*** 1786,1793 ****
  
    let g:linecount = 0
    let arg = 'import os,sys;os.close(1);sys.stderr.write("test\n")'
!   call job_start([s:python, '-c', arg], {'callback': 'MyLineCountCb'})
    call WaitForAssert({-> assert_equal(1, g:linecount)})
  endfunc
  
  func Test_job_start_windows()
--- 1798,1806 ----
  
    let g:linecount = 0
    let arg = 'import os,sys;os.close(1);sys.stderr.write("test\n")'
!   call job_start([s:python, '-c', arg], {'callback': {-> execute('let 
g:linecount += 1')}})
    call WaitForAssert({-> assert_equal(1, g:linecount)})
+   unlet g:linecount
  endfunc
  
  func Test_job_start_windows()
*** ../vim-8.1.0992/src/version.c       2019-03-04 11:40:06.274241644 +0100
--- src/version.c       2019-03-04 12:07:44.178258107 +0100
***************
*** 781,782 ****
--- 781,784 ----
  {   /* Add new patch number below this line */
+ /**/
+     993,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
35. Your husband tells you he's had that beard for 2 months.

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Raspunde prin e-mail lui