vim-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
07e4a19795

Use os_open and os_close.

time_settime is N/A, so some parts of the test are disabled.

There's maybe a very, very, very, very small chance the /dev/urandom test fails,
but it shouldn't matter. :P
This commit is contained in:
Sean Dewar
2022-01-09 23:53:55 +00:00
parent 22f0725aac
commit f6a0d5498b
2 changed files with 42 additions and 6 deletions

View File

@@ -10528,16 +10528,44 @@ static void f_stdpath(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// "srand()" function
static void f_srand(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
static int dev_urandom_state = -1; // FAIL or OK once tried
tv_list_alloc_ret(rettv, 4);
if (argvars[0].v_type == VAR_UNKNOWN) {
tv_list_append_number(rettv->vval.v_list, (varnumber_T)time(NULL));
if (dev_urandom_state != FAIL) {
const int fd = os_open("/dev/urandom", O_RDONLY, 0);
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;
tv_list_append_number(rettv->vval.v_list, (varnumber_T)buf.cont.number);
}
os_close(fd);
}
}
if (dev_urandom_state != OK) {
// Reading /dev/urandom doesn't work, fall back to time().
tv_list_append_number(rettv->vval.v_list, (varnumber_T)time(NULL));
}
} else {
bool error = false;
const uint32_t x = tv_get_number_chk(&argvars[0], &error);
if (error) {
return;
}
tv_list_append_number(rettv->vval.v_list, x);
tv_list_append_number(rettv->vval.v_list, (varnumber_T)x);
}
tv_list_append_number(rettv->vval.v_list, 362436069);
tv_list_append_number(rettv->vval.v_list, 521288629);

View File

@@ -11,10 +11,16 @@ func Test_Rand()
" Nvim does not support test_settime
" call test_settime(12341234)
" let s = srand()
" call assert_equal(s, srand())
" call test_settime(12341235)
" call assert_notequal(s, srand())
let 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()
@@ -26,6 +32,8 @@ 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
" vim: shiftwidth=2 sts=2 expandtab