changeset 8404:8894d595b786 v7.4.1493

commit https://github.com/vim/vim/commit/5983ad0b038fa689653246cb304fd43e8ae39a78 Author: Bram Moolenaar <Bram@vim.org> Date: Sat Mar 5 20:54:36 2016 +0100 patch 7.4.1493 Problem: Wrong callback invoked for zero-id messages. Solution: Don't use the first one-time callback when the sequence number doesn't match.
author Christian Brabandt <cb@256bit.org>
date Sat, 05 Mar 2016 21:00:05 +0100
parents 40c74c3734d7
children c440e8a53d6c
files src/channel.c src/testdir/test_channel.py src/testdir/test_channel.vim src/version.c
diffstat 4 files changed, 79 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/src/channel.c
+++ b/src/channel.c
@@ -1480,7 +1480,7 @@ may_invoke_callback(channel_T *channel, 
     int		seq_nr = -1;
     ch_mode_T	ch_mode = channel->ch_part[part].ch_mode;
     cbq_T	*cbhead = &channel->ch_part[part].ch_cb_head;
-    cbq_T	*cbitem = cbhead->cq_next;
+    cbq_T	*cbitem;
     char_u	*callback = NULL;
     buf_T	*buffer = NULL;
 
@@ -1488,7 +1488,10 @@ may_invoke_callback(channel_T *channel, 
 	/* this channel is handled elsewhere (netbeans) */
 	return FALSE;
 
-    /* use a message-specific callback, part callback or channel callback */
+    /* Use a message-specific callback, part callback or channel callback */
+    for (cbitem = cbhead->cq_next; cbitem != NULL; cbitem = cbitem->cq_next)
+	if (cbitem->cq_seq_nr == 0)
+	    break;
     if (cbitem != NULL)
 	callback = cbitem->cq_callback;
     else if (channel->ch_part[part].ch_callback != NULL)
@@ -1610,16 +1613,13 @@ may_invoke_callback(channel_T *channel, 
 	int	done = FALSE;
 
 	/* invoke the one-time callback with the matching nr */
-	while (cbitem != NULL)
-	{
+	for (cbitem = cbhead->cq_next; cbitem != NULL; cbitem = cbitem->cq_next)
 	    if (cbitem->cq_seq_nr == seq_nr)
 	    {
 		invoke_one_time_callback(channel, cbhead, cbitem, argv);
 		done = TRUE;
 		break;
 	    }
-	    cbitem = cbitem->cq_next;
-	}
 	if (!done)
 	    ch_logn(channel, "Dropping message %d without callback", seq_nr);
     }
--- a/src/testdir/test_channel.py
+++ b/src/testdir/test_channel.py
@@ -143,6 +143,11 @@ class ThreadedTCPRequestHandler(socketse
                         print("sending: {}".format(cmd))
                         self.request.sendall(cmd.encode('utf-8'))
                         response = ""
+                    elif decoded[1] == 'send zero':
+                        cmd = '[0,"zero index"]'
+                        print("sending: {}".format(cmd))
+                        self.request.sendall(cmd.encode('utf-8'))
+                        response = "sent zero"
                     elif decoded[1] == 'close me':
                         print("closing")
                         self.request.close()
--- a/src/testdir/test_channel.vim
+++ b/src/testdir/test_channel.vim
@@ -294,6 +294,72 @@ endfunc
 
 """""""""
 
+let s:ch_reply = ''
+func s:ChHandler(chan, msg)
+  unlet s:ch_reply
+  let s:ch_reply = a:msg
+endfunc
+
+let s:zero_reply = ''
+func s:OneHandler(chan, msg)
+  unlet s:zero_reply
+  let s:zero_reply = a:msg
+endfunc
+
+func s:channel_zero(port)
+  let handle = ch_open('localhost:' . a:port, s:chopt)
+  if ch_status(handle) == "fail"
+    call assert_false(1, "Can't open channel")
+    return
+  endif
+
+  " Check that eval works.
+  call assert_equal('got it', ch_evalexpr(handle, 'hello!'))
+
+  " Check that eval works if a zero id message is sent back.
+  let s:ch_reply = ''
+  call assert_equal('sent zero', ch_evalexpr(handle, 'send zero'))
+  sleep 10m
+  if s:has_handler
+    call assert_equal('zero index', s:ch_reply)
+  else
+    call assert_equal('', s:ch_reply)
+  endif
+
+  " Check that handler works if a zero id message is sent back.
+  let s:ch_reply = ''
+  let s:zero_reply = ''
+  call ch_sendexpr(handle, 'send zero', {'callback': 's:OneHandler'})
+  " Somehow the second message takes a bit of time.
+  for i in range(50)
+    if s:zero_reply == 'sent zero'
+      break
+    endif
+    sleep 10m
+  endfor
+  if s:has_handler
+    call assert_equal('zero index', s:ch_reply)
+  else
+    call assert_equal('', s:ch_reply)
+  endif
+  call assert_equal('sent zero', s:zero_reply)
+endfunc
+
+func Test_zero_reply()
+  call ch_log('Test_zero_reply()')
+  " Run with channel handler
+  let s:has_handler = 1
+  let s:chopt.callback = 's:ChHandler'
+  call s:run_server('s:channel_zero')
+  unlet s:chopt.callback
+
+  " Run without channel handler
+  let s:has_handler = 0
+  call s:run_server('s:channel_zero')
+endfunc
+
+"""""""""
+
 let s:reply1 = ""
 func s:HandleRaw1(chan, msg)
   unlet s:reply1
--- a/src/version.c
+++ b/src/version.c
@@ -744,6 +744,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1493,
+/**/
     1492,
 /**/
     1491,