summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2018-08-06 13:52:15 +0200
committerRalf Jung <post@ralfj.de>2018-08-06 13:52:15 +0200
commit22457deef7e4205b46127fbbe4d0c720aa60b999 (patch)
tree1349a8979095dd807a9a0d698fa26e74af897488 /src/libstd
parent819645bfc461af9c02aa60a3385b008f490ed164 (diff)
downloadrust-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.rs6
-rw-r--r--src/libstd/io/stdio.rs10
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,