Skip to content

Commit 3dc152b

Browse files
vtjnashKristofferC
authored andcommitted
fix Libc.rand and seed problems (#44432)
Continuation from #43606 - Replaces thread-unsafe function `rand` with `jl_rand`. - Fixes `_ad_hoc_entropy_source` fallback in Random. - Uses uv_random for more direct access to quality-randomness (usually a syscall rather than a file.) - Ensures Array{Bool} are valid when created from RandomDevice. (cherry picked from commit b4bed71)
1 parent c8c6cc7 commit 3dc152b

21 files changed

+119
-205
lines changed

base/Base.jl

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -292,9 +292,6 @@ include("process.jl")
292292
include("ttyhascolor.jl")
293293
include("secretbuffer.jl")
294294

295-
# RandomDevice support
296-
include("randomdevice.jl")
297-
298295
# core math functions
299296
include("floatfuncs.jl")
300297
include("math.jl")
@@ -484,8 +481,6 @@ end
484481

485482
if is_primary_base_module
486483
function __init__()
487-
# for the few uses of Libc.rand in Base:
488-
Libc.srand()
489484
# Base library init
490485
reinit_stdio()
491486
Multimedia.reinit_displays() # since Multimedia.displays uses stdout as fallback

base/error.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ function iterate(ebo::ExponentialBackOff, state= (ebo.n, min(ebo.first_delay, eb
261261
state[1] < 1 && return nothing
262262
next_n = state[1]-1
263263
curr_delay = state[2]
264-
next_delay = min(ebo.max_delay, state[2] * ebo.factor * (1.0 - ebo.jitter + (rand(Float64) * 2.0 * ebo.jitter)))
264+
next_delay = min(ebo.max_delay, state[2] * ebo.factor * (1.0 - ebo.jitter + (Libc.rand(Float64) * 2.0 * ebo.jitter)))
265265
(curr_delay, (next_n, next_delay))
266266
end
267267
length(ebo::ExponentialBackOff) = ebo.n

base/libc.jl

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ time() = ccall(:jl_clock_now, Float64, ())
255255
256256
Get Julia's process ID.
257257
"""
258-
getpid() = ccall(:jl_getpid, Int32, ())
258+
getpid() = ccall(:uv_os_getpid, Int32, ())
259259

260260
## network functions ##
261261

@@ -376,31 +376,35 @@ free(p::Cwstring) = free(convert(Ptr{Cwchar_t}, p))
376376

377377
## Random numbers ##
378378

379+
# Access to very high quality (kernel) randomness
380+
function getrandom!(A::Union{Array,Base.RefValue})
381+
ret = ccall(:uv_random, Cint, (Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cvoid}, Csize_t, Cuint, Ptr{Cvoid}),
382+
C_NULL, C_NULL, A, sizeof(A), 0, C_NULL)
383+
Base.uv_error("getrandom", ret)
384+
return A
385+
end
386+
_make_uint64_seed() = getrandom!(Base.RefValue{UInt64}())[]
387+
379388
# To limit dependency on rand functionality implemented in the Random module,
380-
# Libc.rand is used in file.jl, and could be used in error.jl (but it breaks a test)
389+
# Libc.rand is used in Base (it also is independent from Random.seed, so is
390+
# only affected by `Libc.srand(seed)` calls)
381391
"""
382-
rand([T::Type])
392+
rand([T::Type]=UInt32)
383393
384-
Interface to the C `rand()` function. If `T` is provided, generate a value of type `T`
385-
by composing two calls to `rand()`. `T` can be `UInt32` or `Float64`.
394+
Generate a random number of type `T`. `T` can be `UInt32` or `Float64`.
386395
"""
387-
rand() = ccall(:rand, Cint, ())
388-
@static if Sys.iswindows()
389-
# Windows RAND_MAX is 2^15-1
390-
rand(::Type{UInt32}) = ((rand() % UInt32) << 17) ((rand() % UInt32) << 8) (rand() % UInt32)
391-
else
392-
# RAND_MAX is at least 2^15-1 in theory, but we assume 2^16-1
393-
# on non-Windows systems (in practice, it's 2^31-1)
394-
rand(::Type{UInt32}) = ((rand() % UInt32) << 16) (rand() % UInt32)
395-
end
396-
rand(::Type{Float64}) = rand(UInt32) * 2.0^-32
396+
rand() = ccall(:jl_rand, UInt64, ()) % UInt32
397+
rand(::Type{UInt32}) = rand()
398+
rand(::Type{Float64}) = rand() * 2.0^-32
397399

398400
"""
399401
srand([seed])
400402
401-
Interface to the C `srand(seed)` function.
403+
Set a value for the current global `seed`.
402404
"""
403-
srand(seed=Base._make_uint_seed()) = ccall(:srand, Cvoid, (Cuint,), seed)
405+
function srand(seed::Integer=_make_uint64_seed())
406+
ccall(:jl_srand, Cvoid, (UInt64,), seed % UInt64)
407+
end
404408

405409
struct Cpasswd
406410
username::Cstring

base/randomdevice.jl

Lines changed: 0 additions & 77 deletions
This file was deleted.

src/coverage.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,14 +201,14 @@ extern "C" JL_DLLEXPORT void jl_write_coverage_data(const char *output)
201201
}
202202
else {
203203
std::string stm;
204-
raw_string_ostream(stm) << "." << jl_getpid() << ".cov";
204+
raw_string_ostream(stm) << "." << uv_os_getpid() << ".cov";
205205
write_log_data(coverageData, stm.c_str());
206206
}
207207
}
208208

209209
extern "C" JL_DLLEXPORT void jl_write_malloc_log(void)
210210
{
211211
std::string stm;
212-
raw_string_ostream(stm) << "." << jl_getpid() << ".mem";
212+
raw_string_ostream(stm) << "." << uv_os_getpid() << ".mem";
213213
write_log_data(mallocData, stm.c_str());
214214
}

src/gc-debug.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -467,10 +467,9 @@ static void gc_debug_alloc_init(jl_alloc_num_t *num, const char *name)
467467
return;
468468
if (*env == 'r') {
469469
env++;
470-
srand((unsigned)uv_hrtime());
471470
for (int i = 0;i < 3;i++) {
472471
while (num->random[i] == 0) {
473-
num->random[i] = rand();
472+
num->random[i] = jl_rand();
474473
}
475474
}
476475
}

src/init.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,7 @@ JL_DLLEXPORT void julia_init(JL_IMAGE_SEARCH rel)
685685
jl_error("cannot generate code-coverage or track allocation information while generating a .o, .bc, or .s output file");
686686
}
687687

688+
jl_init_rand();
688689
jl_init_runtime_ccall();
689690
jl_init_tasks();
690691
jl_init_threading();

src/jl_exported_funcs.inc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,6 @@
201201
XX(jl_getallocationgranularity) \
202202
XX(jl_getnameinfo) \
203203
XX(jl_getpagesize) \
204-
XX(jl_getpid) \
205204
XX(jl_get_ARCH) \
206205
XX(jl_get_backtrace) \
207206
XX(jl_get_binding) \

src/jl_uv.c

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -641,15 +641,6 @@ JL_DLLEXPORT void jl_exit(int exitcode)
641641
exit(exitcode);
642642
}
643643

644-
JL_DLLEXPORT int jl_getpid(void) JL_NOTSAFEPOINT
645-
{
646-
#ifdef _OS_WINDOWS_
647-
return GetCurrentProcessId();
648-
#else
649-
return getpid();
650-
#endif
651-
}
652-
653644
typedef union {
654645
struct sockaddr in;
655646
struct sockaddr_in v4;

src/julia.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1880,10 +1880,7 @@ typedef struct _jl_task_t {
18801880
jl_value_t *result;
18811881
jl_value_t *logstate;
18821882
jl_function_t *start;
1883-
uint64_t rngState0; // really rngState[4], but more convenient to split
1884-
uint64_t rngState1;
1885-
uint64_t rngState2;
1886-
uint64_t rngState3;
1883+
uint64_t rngState[4];
18871884
_Atomic(uint8_t) _state;
18881885
uint8_t sticky; // record whether this Task can be migrated to a new thread
18891886
_Atomic(uint8_t) _isexception; // set if `result` is an exception to throw or that we exited with

0 commit comments

Comments
 (0)