make Lazy::new unsafe and check reentrancy condition in the callers

This commit is contained in:
Ralf Jung 2018-08-06 13:52:15 +02:00
parent 819645bfc4
commit 22457deef7
2 changed files with 11 additions and 5 deletions

View file

@ -26,7 +26,9 @@ const fn done<T>() -> *mut Arc<T> { 1_usize as *mut _ }
unsafe impl<T> Sync for Lazy<T> {}
impl<T: Send + Sync + 'static> Lazy<T> {
pub const fn new(init: fn() -> Arc<T>) -> Lazy<T> {
/// Safety: `init` must not call `get` on the variable that is being
/// initialized.
pub const unsafe fn new(init: fn() -> Arc<T>) -> Lazy<T> {
// `lock` is never initialized fully, so this mutex is reentrant!
// Do not use it in a way that might be reentrant, that could lead to
// aliasing `&mut`.
@ -66,7 +68,7 @@ impl<T: Send + Sync + 'static> Lazy<T> {
});
// This could reentrantly call `init` again, which is a problem
// because our `lock` allows reentrancy!
// FIXME: Add argument why this is okay.
// That's why `new` is unsafe and requires the caller to ensure no reentrancy happens.
let ret = (self.init)();
if registered.is_ok() {
self.ptr.set(Box::into_raw(Box::new(ret.clone())));

View file

@ -197,12 +197,13 @@ pub struct StdinLock<'a> {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stdin() -> Stdin {
static INSTANCE: Lazy<Mutex<BufReader<Maybe<StdinRaw>>>> = Lazy::new(stdin_init);
static INSTANCE: Lazy<Mutex<BufReader<Maybe<StdinRaw>>>> = unsafe { Lazy::new(stdin_init) };
return Stdin {
inner: INSTANCE.get().expect("cannot access stdin during shutdown"),
};
fn stdin_init() -> Arc<Mutex<BufReader<Maybe<StdinRaw>>>> {
// This must not reentrantly access `INSTANCE`
let stdin = match stdin_raw() {
Ok(stdin) => Maybe::Real(stdin),
_ => Maybe::Fake
@ -396,12 +397,13 @@ pub struct StdoutLock<'a> {
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stdout() -> Stdout {
static INSTANCE: Lazy<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>>
= Lazy::new(stdout_init);
= unsafe { Lazy::new(stdout_init) };
return Stdout {
inner: INSTANCE.get().expect("cannot access stdout during shutdown"),
};
fn stdout_init() -> Arc<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>> {
// This must not reentrantly access `INSTANCE`
let stdout = match stdout_raw() {
Ok(stdout) => Maybe::Real(stdout),
_ => Maybe::Fake,
@ -531,12 +533,14 @@ pub struct StderrLock<'a> {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stderr() -> Stderr {
static INSTANCE: Lazy<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> = Lazy::new(stderr_init);
static INSTANCE: Lazy<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> =
unsafe { Lazy::new(stderr_init) };
return Stderr {
inner: INSTANCE.get().expect("cannot access stderr during shutdown"),
};
fn stderr_init() -> Arc<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> {
// This must not reentrantly access `INSTANCE`
let stderr = match stderr_raw() {
Ok(stderr) => Maybe::Real(stderr),
_ => Maybe::Fake,