docopt/docopt.rs

Docopt can cause a process to block when used before random pool is initialized

Closed this issue · 8 comments

Docopt can cause a process to block if the /dev/urandom pool has not yet been initialized.

Background

On more recent kernels (>3.17), the getrandom syscall has been introduced. This syscall is used by OsRng when getting a random number. The current syscall args cause it to block until the /dev/urandom pool has been initialized. The default implementation of HashMap uses RandomState for its default hasher. RandomState uses the rand crate which blocks until the /dev/urandom pool has been initialized.

System Setup

Ubuntu 15.10
Rust 1.7.0

GDB Backtrace

Catchpoint 1 (call to syscall 318), syscall () at ../sysdeps/unix/sysv/linux/x86_64/syscall.S:38
38  ../sysdeps/unix/sysv/linux/x86_64/syscall.S: No such file or directory.
(gdb) bt
#0  syscall () at ../sysdeps/unix/sysv/linux/x86_64/syscall.S:38
#1  0x00005555558190f5 in rand::StdRng::new::h7f6f37b37bd8a656XMy ()
#2  0x0000555555819446 in rand::thread_rng::THREAD_RNG_KEY::__init::hee923a4dca76e52cqQy ()
#3  0x0000555555801fee in rand::thread_rng::hf965b6c3dc392e76dQy ()
#4  0x0000555555629888 in docopt::collections::hash::map::RandomState::new () at ../src/libstd/collections/hash/map.rs:1638
#5  0x0000555555629864 in docopt::collections::hash::map::RandomState.Default::default () at ../src/libstd/collections/hash/map.rs:1656
#6  0x000055555562ee6f in docopt::collections::hash::map::HashMap<K, V, S>.Default::default () at ../src/libstd/collections/hash/map.rs:1261
#7  0x000055555562ee44 in docopt::collections::hash::map::HashMap<K, V, RandomState>::new () at ../src/libstd/collections/hash/map.rs:512
#8  0x000055555562edef in docopt::synonym::SynonymMap<K, V>::new () at /root/.cargo/registry/src/github.com-88ac128001ac3a9a/docopt-0.6.78/src/synonym.rs:17
#9  0x000055555562e704 in docopt::parse::Parser::new (doc=...) at /root/.cargo/registry/src/github.com-88ac128001ac3a9a/docopt-0.6.78/src/parse.rs:78
#10 0x00005555555cb238 in myprog::dopt::Docopt::new<&str> (usage=...) at /root/.cargo/registry/src/github.com-88ac128001ac3a9a/docopt-0.6.78/src/dopt.rs:177
#11 0x00005555555c7dc2 in myprog::main () at src/main.rs:101
#12 0x0000555555818505 in sys_common::unwind::try::try_fn::h9896872240422604242 ()
#13 0x00005555558157a9 in __rust_try ()
#14 0x0000555555818191 in rt::lang_start::h0d9dcd8707a91319Uoy ()
#15 0x00005555555f518a in main () at ../src/libcollections/string.rs:1734

This may be solved by using a hasher that does not rely on the random pool being initialized.

I feel like "don't ever use the default HashMap" probably isn't a good fix for this. :-/ There are oodles of things that use a HashMap, so I can't imagine that Docopt will be the only problem.

It looks like there was chatter about changing the default hasher for HashMap in rust-lang/rust#27242 and rust-lang/rust#27713. While I agree with you that its not just Docopt that will have this issue this is a concrete example where it causes problems. On some embedded Linux boards that I've got I have had to stop using Docopt for programs that are kicked off by init scripts because it takes about 2 minutes to initialize the random pool and as a result Docopt blocks those programs from starting up for 2 minutes.

You also wouldn't be able to use regex (which uses hash maps internally).

Right. I was going to open an issue there as well.

I suspect the more appropriate place to file an issue is on rust-lang/rust itself, since this is specifically a problem with the default HashMap implementation.

This can be closed since rust-lang/rust#33086 landed.

@cardoe Thanks! :)