]> granicus.if.org Git - vim/commitdiff
patch 8.1.2343: using time() for srand() is not very random v8.1.2343
authorBram Moolenaar <Bram@vim.org>
Tue, 26 Nov 2019 11:23:30 +0000 (12:23 +0100)
committerBram Moolenaar <Bram@vim.org>
Tue, 26 Nov 2019 11:23:30 +0000 (12:23 +0100)
Problem:    Using time() for srand() is not very random.
Solution:   use /dev/urandom if available

src/evalfunc.c
src/testdir/test_random.vim
src/version.c

index a3e5b3e380bd0ef6058e778cc542c99517d02cef..c6e4679e54ba92c38a79fe5295d3524e3341f05e 100644 (file)
@@ -7095,10 +7095,45 @@ f_sqrt(typval_T *argvars, typval_T *rettv)
     static void
 f_srand(typval_T *argvars, typval_T *rettv)
 {
+    static int dev_urandom_state = -1;  // FAIL or OK once tried
+
     if (rettv_list_alloc(rettv) == FAIL)
        return;
     if (argvars[0].v_type == VAR_UNKNOWN)
-       list_append_number(rettv->vval.v_list, (varnumber_T)vim_time());
+    {
+       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;
+                   list_append_number(rettv->vval.v_list,
+                                                (varnumber_T)buf.cont.number);
+               }
+               close(fd);
+           }
+
+       }
+       if (dev_urandom_state != OK)
+           // Reading /dev/urandom doesn't work, fall back to time().
+           list_append_number(rettv->vval.v_list, (varnumber_T)vim_time());
+    }
     else
     {
        int         error = FALSE;
@@ -7107,7 +7142,7 @@ f_srand(typval_T *argvars, typval_T *rettv)
        if (error)
            return;
 
-       list_append_number(rettv->vval.v_list, x);
+       list_append_number(rettv->vval.v_list, (varnumber_T)x);
     }
     list_append_number(rettv->vval.v_list, 362436069);
     list_append_number(rettv->vval.v_list, 521288629);
index 381475a43f5f636a7754ec973f241a06f3a10bef..9fe71a98c453e0b3b9d8c2f2372e97e566005cd8 100644 (file)
@@ -11,9 +11,15 @@ func Test_Rand()
 
   call test_settime(12341234)
   let s = srand()
-  call assert_equal(s, srand())
-  call test_settime(12341235)
-  call assert_notequal(s, srand())
+  if filereadable('/dev/urandom')
+    " using /dev/urandom
+    call assert_notequal(s, srand())
+  else
+    " using time()
+    call assert_equal(s, srand())
+    call test_settime(12341235)
+    call assert_notequal(s, srand())
+  endif
 
   call srand()
   let v = rand()
@@ -25,4 +31,6 @@ func Test_Rand()
   call assert_fails('echo rand([1, [2], 3, 4])', 'E475:')
   call assert_fails('echo rand([1, 2, [3], 4])', 'E475:')
   call assert_fails('echo rand([1, 2, 3, [4]])', 'E475:')
+
+  call test_settime(0)
 endfunc
index f88d0e9adc09b38bed1509e4d43a467ad41292fd..9b8a02fac1ddd5a102ffb706bde6f289034eb77f 100644 (file)
@@ -737,6 +737,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2343,
 /**/
     2342,
 /**/