Patch 8.1.1512
Problem:    ch_evalexpr() hangs when used recursively. (Paul Jolly)
Solution:   Change ch_block_id from a single number to a list of IDs to wait
            on.
Files:      src/channel.c, src/structs.h


*** ../vim-8.1.1511/src/channel.c       2019-06-03 21:14:55.129048884 +0200
--- src/channel.c       2019-06-09 19:42:30.139390195 +0200
***************
*** 2154,2163 ****
  }
  
  /*
   * Get a message from the JSON queue for channel "channel".
   * When "id" is positive it must match the first number in the list.
!  * When "id" is zero or negative jut get the first message.  But not the one
!  * with id ch_block_id.
   * When "without_callback" is TRUE also get messages that were pushed back.
   * Return OK when found and return the value in "rettv".
   * Return FAIL otherwise.
--- 2154,2219 ----
  }
  
  /*
+  * Add "id" to the list of JSON message IDs we are waiting on.
+  */
+     static void
+ channel_add_block_id(chanpart_T *chanpart, int id)
+ {
+     garray_T *gap = &chanpart->ch_block_ids;
+ 
+     if (gap->ga_growsize == 0)
+       ga_init2(gap, (int)sizeof(int), 10);
+     if (ga_grow(gap, 1) == OK)
+     {
+       ((int *)gap->ga_data)[gap->ga_len] = id;
+       ++gap->ga_len;
+     }
+ }
+ 
+ /*
+  * Remove "id" from the list of JSON message IDs we are waiting on.
+  */
+     static void
+ channel_remove_block_id(chanpart_T *chanpart, int id)
+ {
+     garray_T  *gap = &chanpart->ch_block_ids;
+     int               i;
+ 
+     for (i = 0; i < gap->ga_len; ++i)
+       if (((int *)gap->ga_data)[i] == id)
+       {
+           --gap->ga_len;
+           if (i < gap->ga_len)
+           {
+               int *p = ((int *)gap->ga_data) + i;
+ 
+               mch_memmove(p, p + 1, (gap->ga_len - i) * sizeof(int));
+           }
+           return;
+       }
+     siemsg("INTERNAL: channel_remove_block_id: cannot find id %d", id);
+ }
+ 
+ /*
+  * Return TRUE if "id" is in the list of JSON message IDs we are waiting on.
+  */
+     static int
+ channel_has_block_id(chanpart_T *chanpart, int id)
+ {
+     garray_T  *gap = &chanpart->ch_block_ids;
+     int               i;
+ 
+     for (i = 0; i < gap->ga_len; ++i)
+       if (((int *)gap->ga_data)[i] == id)
+           return TRUE;
+     return FALSE;
+ }
+ 
+ /*
   * Get a message from the JSON queue for channel "channel".
   * When "id" is positive it must match the first number in the list.
!  * When "id" is zero or negative jut get the first message.  But not one
!  * in the ch_block_ids list.
   * When "without_callback" is TRUE also get messages that were pushed back.
   * Return OK when found and return the value in "rettv".
   * Return FAIL otherwise.
***************
*** 2182,2188 ****
            && ((id > 0 && tv->v_type == VAR_NUMBER && tv->vval.v_number == id)
              || (id <= 0 && (tv->v_type != VAR_NUMBER
                 || tv->vval.v_number == 0
!                || tv->vval.v_number != channel->ch_part[part].ch_block_id))))
        {
            *rettv = item->jq_value;
            if (tv->v_type == VAR_NUMBER)
--- 2238,2245 ----
            && ((id > 0 && tv->v_type == VAR_NUMBER && tv->vval.v_number == id)
              || (id <= 0 && (tv->v_type != VAR_NUMBER
                 || tv->vval.v_number == 0
!                || !channel_has_block_id(
!                               &channel->ch_part[part], tv->vval.v_number)))))
        {
            *rettv = item->jq_value;
            if (tv->v_type == VAR_NUMBER)
***************
*** 3050,3055 ****
--- 3107,3113 ----
      }
  
      free_callback(&ch_part->ch_callback);
+     ga_clear(&ch_part->ch_block_ids);
  
      while (ch_part->ch_writeque.wq_next != NULL)
        remove_from_writeque(&ch_part->ch_writeque,
***************
*** 3480,3485 ****
--- 3538,3545 ----
   * result in "rettv".
   * When "id" is -1 accept any message;
   * Blocks until the message is received or the timeout is reached.
+  * In corner cases this can be called recursively, that is why ch_block_ids is
+  * a list.
   */
      static int
  channel_read_json_block(
***************
*** 3494,3510 ****
      int               timeout;
      chanpart_T        *chanpart = &channel->ch_part[part];
  
!     ch_log(channel, "Reading JSON");
!     if (id != -1)
!       chanpart->ch_block_id = id;
      for (;;)
      {
        more = channel_parse_json(channel, part);
  
!       /* search for message "id" */
        if (channel_get_json(channel, part, id, TRUE, rettv) == OK)
        {
!           chanpart->ch_block_id = 0;
            return OK;
        }
  
--- 3554,3572 ----
      int               timeout;
      chanpart_T        *chanpart = &channel->ch_part[part];
  
!     ch_log(channel, "Blocking read JSON for id %d", id);
!     if (id >= 0)
!       channel_add_block_id(chanpart, id);
      for (;;)
      {
        more = channel_parse_json(channel, part);
  
!       // search for message "id"
        if (channel_get_json(channel, part, id, TRUE, rettv) == OK)
        {
!           if (id >= 0)
!               channel_remove_block_id(chanpart, id);
!           ch_log(channel, "Received JSON for id %d", id);
            return OK;
        }
  
***************
*** 3551,3557 ****
                if (timeout == timeout_arg)
                {
                    if (fd != INVALID_FD)
!                       ch_log(channel, "Timed out");
                    break;
                }
            }
--- 3613,3619 ----
                if (timeout == timeout_arg)
                {
                    if (fd != INVALID_FD)
!                       ch_log(channel, "Timed out on id %d", id);
                    break;
                }
            }
***************
*** 3559,3565 ****
                channel_read(channel, part, "channel_read_json_block");
        }
      }
!     chanpart->ch_block_id = 0;
      return FAIL;
  }
  
--- 3621,3628 ----
                channel_read(channel, part, "channel_read_json_block");
        }
      }
!     if (id >= 0)
!       channel_remove_block_id(chanpart, id);
      return FAIL;
  }
  
*** ../vim-8.1.1511/src/structs.h       2019-06-08 16:06:25.454274085 +0200
--- src/structs.h       2019-06-09 19:13:44.227389731 +0200
***************
*** 1680,1687 ****
  
      readq_T   ch_head;        /* header for circular raw read queue */
      jsonq_T   ch_json_head;   /* header for circular json read queue */
!     int               ch_block_id;    /* ID that channel_read_json_block() is
!                                  waiting for */
      /* When ch_wait_len is non-zero use ch_deadline to wait for incomplete
       * message to be complete. The value is the length of the incomplete
       * message when the deadline was set.  If it gets longer (something was
--- 1680,1687 ----
  
      readq_T   ch_head;        /* header for circular raw read queue */
      jsonq_T   ch_json_head;   /* header for circular json read queue */
!     garray_T  ch_block_ids;   /* list of IDs that channel_read_json_block()
!                                  is waiting for */
      /* When ch_wait_len is non-zero use ch_deadline to wait for incomplete
       * message to be complete. The value is the length of the incomplete
       * message when the deadline was set.  If it gets longer (something was
*** ../vim-8.1.1511/src/version.c       2019-06-09 18:04:09.839426999 +0200
--- src/version.c       2019-06-09 19:51:03.112811393 +0200
***************
*** 779,780 ****
--- 779,782 ----
  {   /* Add new patch number below this line */
+ /**/
+     1512,
  /**/

-- 
Amazing but true: If all the salmon caught in Canada in one year were laid
end to end across the Sahara Desert, the smell would be absolutely awful.

 /// 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].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/201906091752.x59HqO1e029098%40masaka.moolenaar.net.
For more options, visit https://groups.google.com/d/optout.

Raspunde prin e-mail lui