-
Notifications
You must be signed in to change notification settings - Fork 728
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
rand: replace lazy_static with std::sync::Once #711
Conversation
@bpowers, thanks for writing this! I'm going to review this PR line-by-line, then I'll explain the mistake I made in asking for this change. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, I definitely like getting rid of the lazy_static
dependency.
However, I did not realize that we'd have to add new uses of unsafe
in the code by switching to a raw static mut
, as I'd never used static mut
before. In hindsight, this is obvious, but it just hadn't occured to me.
Definitely we shouldn't put new unsafe
uses in ring::rand
; either we should implement this in polyfill
or we should continue depending on a third-party crate, be it lazy_static
or one of the simpler alternatives. I'm not sure which course of action is best. WDYT?
@@ -197,23 +197,32 @@ mod urandom { | |||
use std; | |||
use error; | |||
|
|||
pub fn fill(dest: &mut [u8]) -> Result<(), error::Unspecified> { | |||
fn get_random_file() -> &'static Option<std::fs::File> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It took me a while to understand that you factored out get_random_file()
as a function because you wanted to limit access to FILE
to avoid the potential safety issues that are inherent in static mut
. It is important to document this so that people don't refactor the code to remove this extra level of safety.
Normally we document such things, especially things that use unsafe
, by (1) factoring the code out into its own module under the polyfill
submodule, and (2) writing comments.
In this case, that would basically be re-implementing lazy_static
and other similar crates. We could do it a lot simpler than lazy_static
since this code doesn't need no_std
support and it doesn't need to work on old versions of Rust, so we could avoid the version_check
dependency that lazy_static
has. However, I think there are probably better alternative crates to lazy_static
that we could/should use instead of implementing it ourselves in polyfill
. We should evaluate those alternatives vs. lazy_static
and vs. implementing it ourselves.
If we are going to maintain our own implementation of this, then (1) it should be a polyfill
submodule, and (2) we should document why we're implementing it, e.g. by documenting the issues that other crates have, noting that build speed is faster (almost definitely), noting that we don't have to track third-party dependency (lazy_static
and version_check
, compared to lazy_static
), avoiding one heap allocation, simpler code, and any other benefits.
use std::sync::Once; | ||
|
||
static mut FILE: Option<std::fs::File> = None; | ||
static FILE_INIT: Once = Once::new(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think _ONCE
would be a better naming convention than _INIT
.
static mut FILE: Option<std::fs::File> = None; | ||
static FILE_INIT: Once = Once::new(); | ||
|
||
unsafe { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's minimize the scope of unsafe { }
. In this case, I think the unsafe {}
should go inside the body of the closure passed to FILE_INIT.call_once
, something like:
FILE_INIT.call_once(|| {
let file = std::fs::File::open(RANDOM_PATH).ok();
unsafe { FILE = file; }
});
unsafe {
&FILE
}
Similarly, the scope of RANDOM_PATH
should be minimized, by moving it into the closure.
use std::sync::Once; | ||
|
||
static mut MECHANISM: Mechanism = Mechanism::Sysrand; | ||
static MECHANISM_INIT: Once = Once::new(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All the issues I pointed out above also apply here.
@bpowers Thank you very much for the PR. I really appreciate your help here. I'm going to close this PR based on the discussion above; I will explain it in the issue that this PR was attempting to resolve. |
@briansmith sorry I didn't respond sooner -- I agree with what you wrote above and in the issue about |
This replaces the use of
lazy_static
with mutable statics. I'm pretty new to Rust, would love any feedback!fixes #706
I agree to license my contributions to each file under the terms given at the top of each file I changed.