Patch 8.2.0233
Problem:    Crash when using garbagecollect() in between rand().
Solution:   Redesign the rand() and srand() implementation. (Yasuhiro
            Matsumoto, closes #5587, closes #5588)
Files:      src/evalfunc.c, src/testdir/test_random.vim,
            runtime/doc/testing.txt, runtime/doc/eval.txt


*** ../vim-8.2.0232/src/evalfunc.c      2020-02-05 20:38:15.931599558 +0100
--- src/evalfunc.c      2020-02-08 16:36:59.028550580 +0100
***************
*** 168,173 ****
--- 168,174 ----
  #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
  static void f_pyxeval(typval_T *argvars, typval_T *rettv);
  #endif
+ static void f_test_srand_seed(typval_T *argvars, typval_T *rettv);
  static void f_rand(typval_T *argvars, typval_T *rettv);
  static void f_range(typval_T *argvars, typval_T *rettv);
  static void f_reg_executing(typval_T *argvars, typval_T *rettv);
***************
*** 835,840 ****
--- 836,842 ----
  #endif
      {"test_setmouse", 2, 2, 0,          &t_void,      f_test_setmouse},
      {"test_settime",  1, 1, FEARG_1,    &t_void,      f_test_settime},
+     {"test_srand_seed",       0, 1, FEARG_1,    &t_void,      
f_test_srand_seed},
  #ifdef FEAT_TIMERS
      {"timer_info",    0, 1, FEARG_1,    &t_list_dict_any, f_timer_info},
      {"timer_pause",   2, 2, FEARG_1,    &t_void,      f_timer_pause},
***************
*** 5225,5230 ****
--- 5227,5309 ----
  }
  #endif
  
+ static UINT32_T srand_seed_for_testing = 0;
+ static int    srand_seed_for_testing_is_used = FALSE;
+ 
+     static void
+ f_test_srand_seed(typval_T *argvars, typval_T *rettv UNUSED)
+ {
+     if (argvars[0].v_type == VAR_UNKNOWN)
+         srand_seed_for_testing_is_used = FALSE;
+     else
+     {
+         srand_seed_for_testing = (UINT32_T)tv_get_number(&argvars[0]);
+         srand_seed_for_testing_is_used = TRUE;
+     }
+ }
+ 
+     static void
+ init_srand(UINT32_T *x)
+ {
+ #ifndef MSWIN
+     static int dev_urandom_state = NOTDONE;  // FAIL or OK once tried
+ #endif
+ 
+     if (srand_seed_for_testing_is_used)
+     {
+         *x = srand_seed_for_testing;
+       return;
+     }
+ #ifndef MSWIN
+     if (dev_urandom_state != FAIL)
+     {
+       int  fd = open("/dev/urandom", O_RDONLY);
+       struct {
+           union {
+               UINT32_T number;
+               char     bytes[sizeof(UINT32_T)];
+           } contents;
+       } buf;
+ 
+       // Attempt reading /dev/urandom.
+       if (fd == -1)
+           dev_urandom_state = FAIL;
+       else
+       {
+           buf.contents.number = 0;
+           if (read(fd, buf.contents.bytes, sizeof(UINT32_T))
+                                                          != sizeof(UINT32_T))
+               dev_urandom_state = FAIL;
+           else
+           {
+               dev_urandom_state = OK;
+               *x = buf.contents.number;
+           }
+           close(fd);
+       }
+     }
+     if (dev_urandom_state != OK)
+       // Reading /dev/urandom doesn't work, fall back to time().
+ #endif
+       *x = vim_time();
+ }
+ 
+ #define ROTL(x, k) ((x << k) | (x >> (32 - k)))
+ #define SPLITMIX32(x, z) ( \
+     z = (x += 0x9e3779b9), \
+     z = (z ^ (z >> 16)) * 0x85ebca6b, \
+     z = (z ^ (z >> 13)) * 0xc2b2ae35, \
+     z ^ (z >> 16) \
+     )
+ #define SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w) \
+     result = ROTL(y * 5, 7) * 9; \
+     t = y << 9; \
+     z ^= x; \
+     w ^= y; \
+     y ^= z, x ^= w; \
+     z ^= t; \
+     w = ROTL(w, 11);
+ 
  /*
   * "rand()" function
   */
***************
*** 5232,5297 ****
  f_rand(typval_T *argvars, typval_T *rettv)
  {
      list_T    *l = NULL;
!     static list_T *globl = NULL;
!     UINT32_T  x, y, z, w, t, result;
      listitem_T        *lx, *ly, *lz, *lw;
  
      if (argvars[0].v_type == VAR_UNKNOWN)
      {
        // When no argument is given use the global seed list.
!       if (globl == NULL)
        {
            // Initialize the global seed list.
!           f_srand(argvars, rettv);
!           l = rettv->vval.v_list;
!           if (l == NULL || list_len(l) != 4)
!           {
!               clear_tv(rettv);
!               goto theend;
!           }
!           globl = l;
        }
!       else
!           l = globl;
      }
      else if (argvars[0].v_type == VAR_LIST)
      {
        l = argvars[0].vval.v_list;
        if (l == NULL || list_len(l) != 4)
            goto theend;
      }
      else
        goto theend;
  
-     lx = list_find(l, 0L);
-     ly = list_find(l, 1L);
-     lz = list_find(l, 2L);
-     lw = list_find(l, 3L);
-     if (lx->li_tv.v_type != VAR_NUMBER) goto theend;
-     if (ly->li_tv.v_type != VAR_NUMBER) goto theend;
-     if (lz->li_tv.v_type != VAR_NUMBER) goto theend;
-     if (lw->li_tv.v_type != VAR_NUMBER) goto theend;
-     x = (UINT32_T)lx->li_tv.vval.v_number;
-     y = (UINT32_T)ly->li_tv.vval.v_number;
-     z = (UINT32_T)lz->li_tv.vval.v_number;
-     w = (UINT32_T)lw->li_tv.vval.v_number;
- 
-     // SHUFFLE_XOSHIRO128STARSTAR
- #define ROTL(x, k) ((x << k) | (x >> (32 - k)))
-     result = ROTL(y * 5, 7) * 9;
-     t = y << 9;
-     z ^= x;
-     w ^= y;
-     y ^= z, x ^= w;
-     z ^= t;
-     w = ROTL(w, 11);
- #undef ROTL
- 
-     lx->li_tv.vval.v_number = (varnumber_T)x;
-     ly->li_tv.vval.v_number = (varnumber_T)y;
-     lz->li_tv.vval.v_number = (varnumber_T)z;
-     lw->li_tv.vval.v_number = (varnumber_T)w;
- 
      rettv->v_type = VAR_NUMBER;
      rettv->vval.v_number = (varnumber_T)result;
      return;
--- 5311,5367 ----
  f_rand(typval_T *argvars, typval_T *rettv)
  {
      list_T    *l = NULL;
!     static UINT32_T   gx, gy, gz, gw;
!     static int        initialized = FALSE;
      listitem_T        *lx, *ly, *lz, *lw;
+     UINT32_T  x, y, z, w, t, result;
  
      if (argvars[0].v_type == VAR_UNKNOWN)
      {
        // When no argument is given use the global seed list.
!       if (initialized == FALSE)
        {
            // Initialize the global seed list.
!           init_srand(&x);
! 
!           gx = SPLITMIX32(x, z);
!           gy = SPLITMIX32(x, z);
!           gz = SPLITMIX32(x, z);
!           gw = SPLITMIX32(x, z);
!           initialized = TRUE;
        }
! 
!       SHUFFLE_XOSHIRO128STARSTAR(gx, gy, gz, gw);
      }
      else if (argvars[0].v_type == VAR_LIST)
      {
        l = argvars[0].vval.v_list;
        if (l == NULL || list_len(l) != 4)
            goto theend;
+ 
+       lx = list_find(l, 0L);
+       ly = list_find(l, 1L);
+       lz = list_find(l, 2L);
+       lw = list_find(l, 3L);
+       if (lx->li_tv.v_type != VAR_NUMBER) goto theend;
+       if (ly->li_tv.v_type != VAR_NUMBER) goto theend;
+       if (lz->li_tv.v_type != VAR_NUMBER) goto theend;
+       if (lw->li_tv.v_type != VAR_NUMBER) goto theend;
+       x = (UINT32_T)lx->li_tv.vval.v_number;
+       y = (UINT32_T)ly->li_tv.vval.v_number;
+       z = (UINT32_T)lz->li_tv.vval.v_number;
+       w = (UINT32_T)lw->li_tv.vval.v_number;
+ 
+       SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w);
+ 
+       lx->li_tv.vval.v_number = (varnumber_T)x;
+       ly->li_tv.vval.v_number = (varnumber_T)y;
+       lz->li_tv.vval.v_number = (varnumber_T)z;
+       lw->li_tv.vval.v_number = (varnumber_T)w;
      }
      else
        goto theend;
  
      rettv->v_type = VAR_NUMBER;
      rettv->vval.v_number = (varnumber_T)result;
      return;
***************
*** 5303,5308 ****
--- 5373,5411 ----
  }
  
  /*
+  * "srand()" function
+  */
+     static void
+ f_srand(typval_T *argvars, typval_T *rettv)
+ {
+     UINT32_T x = 0, z;
+ 
+     if (rettv_list_alloc(rettv) == FAIL)
+       return;
+     if (argvars[0].v_type == VAR_UNKNOWN)
+     {
+       init_srand(&x);
+     }
+     else
+     {
+       int         error = FALSE;
+ 
+       x = (UINT32_T)tv_get_number_chk(&argvars[0], &error);
+       if (error)
+           return;
+     }
+ 
+     list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
+     list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
+     list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
+     list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
+ }
+ 
+ #undef ROTL
+ #undef SPLITMIX32
+ #undef SHUFFLE_XOSHIRO128STARSTAR
+ 
+ /*
   * "range()" function
   */
      static void
***************
*** 7217,7289 ****
  }
  #endif
  
- /*
-  * "srand()" function
-  */
-     static void
- f_srand(typval_T *argvars, typval_T *rettv)
- {
-     static int dev_urandom_state = -1;  // FAIL or OK once tried
-     UINT32_T x = 0, z;
- 
-     if (rettv_list_alloc(rettv) == FAIL)
-       return;
-     if (argvars[0].v_type == VAR_UNKNOWN)
-     {
-       if (dev_urandom_state != FAIL)
-       {
-           int  fd = open("/dev/urandom", O_RDONLY);
-           struct {
-               union {
-                   UINT32_T number;
-                   char     bytes[sizeof(UINT32_T)];
-               } cont;
-           } buf;
- 
-           // Attempt reading /dev/urandom.
-           if (fd == -1)
-               dev_urandom_state = FAIL;
-           else
-           {
-               buf.cont.number = 0;
-               if (read(fd, buf.cont.bytes, sizeof(UINT32_T))
-                                                          != sizeof(UINT32_T))
-                   dev_urandom_state = FAIL;
-               else
-               {
-                   dev_urandom_state = OK;
-                   x = buf.cont.number;
-               }
-               close(fd);
-           }
- 
-       }
-       if (dev_urandom_state != OK)
-           // Reading /dev/urandom doesn't work, fall back to time().
-           x = vim_time();
-     }
-     else
-     {
-       int         error = FALSE;
- 
-       x = (UINT32_T)tv_get_number_chk(&argvars[0], &error);
-       if (error)
-           return;
-     }
- 
- #define SPLITMIX32 ( \
-     z = (x += 0x9e3779b9), \
-     z = (z ^ (z >> 16)) * 0x85ebca6b, \
-     z = (z ^ (z >> 13)) * 0xc2b2ae35, \
-     z ^ (z >> 16) \
-     )
- 
-     list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32);
-     list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32);
-     list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32);
-     list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32);
- }
- 
  #ifdef FEAT_FLOAT
  /*
   * "str2float()" function
--- 7320,7325 ----
*** ../vim-8.2.0232/src/testdir/test_random.vim 2019-11-28 22:55:18.000000000 
+0100
--- src/testdir/test_random.vim 2020-02-08 16:07:00.083822690 +0100
***************
*** 11,17 ****
  
    call test_settime(12341234)
    let s = srand()
!   if filereadable('/dev/urandom')
      " using /dev/urandom
      call assert_notequal(s, srand())
    else
--- 11,17 ----
  
    call test_settime(12341234)
    let s = srand()
!   if !has('win32') && filereadable('/dev/urandom')
      " using /dev/urandom
      call assert_notequal(s, srand())
    else
***************
*** 21,29 ****
      call assert_notequal(s, srand())
    endif
  
!   call srand()
!   let v = rand()
!   call assert_notequal(v, rand())
  
    if has('float')
      call assert_fails('echo srand(1.2)', 'E805:')
--- 21,30 ----
      call assert_notequal(s, srand())
    endif
  
!   call test_srand_seed(123456789)
!   call assert_equal(4284103975, rand())
!   call assert_equal(1001954530, rand())
!   call test_srand_seed()
  
    if has('float')
      call assert_fails('echo srand(1.2)', 'E805:')
***************
*** 38,40 ****
--- 39,47 ----
  
    call test_settime(0)
  endfunc
+ 
+ func Test_issue_5587()
+   call rand()
+   call garbagecollect()
+   call rand()
+ endfunc
*** ../vim-8.2.0232/runtime/doc/testing.txt     2020-02-05 20:38:15.927599576 
+0100
--- runtime/doc/testing.txt     2020-02-08 16:16:08.797606207 +0100
***************
*** 210,216 ****
                        call test_setmouse(4, 20)
                        call feedkeys("\<LeftMouse>", "xt")
  
- 
  test_settime({expr})                                  *test_settime()*
                Set the time Vim uses internally.  Currently only used for
                timestamps in the history, as they are used in viminfo, and
--- 210,215 ----
***************
*** 223,228 ****
--- 222,231 ----
                Can also be used as a |method|: >
                        GetTime()->test_settime()
  
+ test_srand_seed([seed])                                       
*test_srand_seed()*
+               When [seed] is given this sets the seed value used by
+               `srand()`.  When omitted the test seed is removed.
+ 
  ==============================================================================
  3. Assert functions                           *assert-functions-details*
  
*** ../vim-8.2.0232/runtime/doc/eval.txt        2020-02-05 20:38:15.927599576 
+0100
--- runtime/doc/eval.txt        2020-02-08 16:11:09.918810771 +0100
***************
*** 2865,2870 ****
--- 2867,2873 ----
  test_scrollbar({which}, {value}, {dragging})
                                none    scroll in the GUI for testing
  test_setmouse({row}, {col})   none    set the mouse position for testing
+ test_srand_seed([seed])               none    set seed for testing srand()
  test_settime({expr})          none    set current time for testing
  timer_info([{id}])            List    information about timers
  timer_pause({id}, {pause})    none    pause or unpause a timer
*** ../vim-8.2.0232/src/version.c       2020-02-08 16:00:43.225362846 +0100
--- src/version.c       2020-02-08 16:09:11.663289031 +0100
***************
*** 744,745 ****
--- 744,747 ----
  {   /* Add new patch number below this line */
+ /**/
+     233,
  /**/

-- 
It was recently discovered that research causes cancer in rats.

 /// 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/202002081541.018Ff7Xl023023%40masaka.moolenaar.net.

Raspunde prin e-mail lui