# HG changeset patch # User Bram Moolenaar # Date 1670277605 -3600 # Node ID 0608de1064852a93ac2b845c6cc4a633142e5dce # Parent 7fc63cd1c462705fd867510d4f4390cb2d2d3d8f patch 9.0.1015: without /dev/urandom srand() seed is too predictable Commit: https://github.com/vim/vim/commit/f0a9c004825ab686270ee57260652cce25e61049 Author: Yasuhiro Matsumoto Date: Mon Dec 5 21:55:55 2022 +0000 patch 9.0.1015: without /dev/urandom srand() seed is too predictable Problem: Without /dev/urandom srand() seed is too predictable. Solution: Use micro seconds and XOR with process ID. (Yasuhiro Matsumoto, closes #11656) diff --git a/src/evalfunc.c b/src/evalfunc.c --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -8159,9 +8159,32 @@ init_srand(UINT32_T *x) } } if (dev_urandom_state != OK) - // Reading /dev/urandom doesn't work, fall back to time(). -#endif - *x = vim_time(); +#endif + { + // Reading /dev/urandom doesn't work, fall back to: + // - randombytes_random() + // - reltime() or time() + // - XOR with process ID +#if defined(FEAT_SODIUM) + if (sodium_init() >= 0) + *x = randombytes_random(); + else +#endif + { +#if defined(FEAT_RELTIME) + proftime_T res; + profile_start(&res); +# if defined(MSWIN) + *x = (UINT32_T)res.LowPart; +# else + *x = (UINT32_T)res.tv_usec; +# endif +#else + *x = vim_time(); +#endif + *x ^= mch_get_pid(); + } + } } #define ROTL(x, k) (((x) << (k)) | ((x) >> (32 - (k)))) 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 @@ -1,5 +1,8 @@ " Tests for srand() and rand() +source check.vim +source shared.vim + func Test_Rand() let r = srand(123456789) call assert_equal([1573771921, 319883699, 2742014374, 1324369493], r) @@ -44,4 +47,20 @@ func Test_issue_5587() call rand() endfunc +func Test_srand() + CheckNotGui + + let cmd = GetVimCommand() .. ' -V -es -c "echo rand()" -c qa!' + let bad = 0 + for _ in range(10) + echo cmd + let result1 = system(cmd) + let result2 = system(cmd) + if result1 ==# result2 + let bad += 1 + endif + endfor + call assert_inrange(0, 4, bad) +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -696,6 +696,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1015, +/**/ 1014, /**/ 1013,