diff options
| author | Ralf Jung <post@ralfj.de> | 2018-08-06 13:52:15 +0200 |
|---|---|---|
| committer | Ralf Jung <post@ralfj.de> | 2018-08-06 13:52:15 +0200 |
| commit | 22457deef7e4205b46127fbbe4d0c720aa60b999 (patch) | |
| tree | 1349a8979095dd807a9a0d698fa26e74af897488 /src/libstd | |
| parent | 819645bfc461af9c02aa60a3385b008f490ed164 (diff) | |
| download | rust-22457deef7e4205b46127fbbe4d0c720aa60b999.tar.gz rust-22457deef7e4205b46127fbbe4d0c720aa60b999.zip | |
make Lazy::new unsafe and check reentrancy condition in the callers
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/io/lazy.rs | 6 | ||||
| -rw-r--r-- | src/libstd/io/stdio.rs | 10 |
2 files changed, 11 insertions, 5 deletions
diff --git a/src/libstd/io/lazy.rs b/src/libstd/io/lazy.rs index 09b2ddcbcac..9513cc7fb2d 100644 --- a/src/libstd/io/lazy.rs +++ b/src/libstd/io/lazy.rs @@ -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()))); diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index fffe8fc559b..1f256f518c7 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -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, |
