# HG changeset patch # User Bram Moolenaar # Date 1574767804 -3600 # Node ID aef98a646d3ec797008738f7181729f3540ac1de # Parent fd7bbf832d8f7416f03bad50f8f68d021948f24e patch 8.1.2343: using time() for srand() is not very random Commit: https://github.com/vim/vim/commit/07e4a197953d12902fb97beb48830a5323a52280 Author: Bram Moolenaar 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 diff --git a/src/evalfunc.c b/src/evalfunc.c --- 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); diff --git a/src/testdir/test_random.vim b/src/testdir/test_random.vim --- 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 diff --git a/src/version.c b/src/version.c --- 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,