changeset 18703:aef98a646d3e v8.1.2343

patch 8.1.2343: using time() for srand() is not very random Commit: https://github.com/vim/vim/commit/07e4a197953d12902fb97beb48830a5323a52280 Author: Bram Moolenaar <Bram@vim.org> Date: Tue Nov 26 12:23:30 2019 +0100 patch 8.1.2343: using time() for srand() is not very random Problem: Using time() for srand() is not very random. Solution: use /dev/urandom if available
author Bram Moolenaar <Bram@vim.org>
date Tue, 26 Nov 2019 12:30:04 +0100
parents fd7bbf832d8f
children 65e3c91819fe
files src/evalfunc.c src/testdir/test_random.vim src/version.c
diffstat 3 files changed, 50 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -7095,10 +7095,45 @@ f_sqrt(typval_T *argvars, typval_T *rett
     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 *ret
 	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);
--- a/src/testdir/test_random.vim
+++ b/src/testdir/test_random.vim
@@ -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
--- a/src/version.c
+++ b/src/version.c
@@ -738,6 +738,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    2343,
+/**/
     2342,
 /**/
     2341,