Skip to content

Commit 22457de

Browse files
committed
make Lazy::new unsafe and check reentrancy condition in the callers
1 parent 819645b commit 22457de

File tree

2 files changed

+11
-5
lines changed

2 files changed

+11
-5
lines changed

src/libstd/io/lazy.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ const fn done<T>() -> *mut Arc<T> { 1_usize as *mut _ }
2626
unsafe impl<T> Sync for Lazy<T> {}
2727

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

src/libstd/io/stdio.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -197,12 +197,13 @@ pub struct StdinLock<'a> {
197197
/// ```
198198
#[stable(feature = "rust1", since = "1.0.0")]
199199
pub fn stdin() -> Stdin {
200-
static INSTANCE: Lazy<Mutex<BufReader<Maybe<StdinRaw>>>> = Lazy::new(stdin_init);
200+
static INSTANCE: Lazy<Mutex<BufReader<Maybe<StdinRaw>>>> = unsafe { Lazy::new(stdin_init) };
201201
return Stdin {
202202
inner: INSTANCE.get().expect("cannot access stdin during shutdown"),
203203
};
204204

205205
fn stdin_init() -> Arc<Mutex<BufReader<Maybe<StdinRaw>>>> {
206+
// This must not reentrantly access `INSTANCE`
206207
let stdin = match stdin_raw() {
207208
Ok(stdin) => Maybe::Real(stdin),
208209
_ => Maybe::Fake
@@ -396,12 +397,13 @@ pub struct StdoutLock<'a> {
396397
#[stable(feature = "rust1", since = "1.0.0")]
397398
pub fn stdout() -> Stdout {
398399
static INSTANCE: Lazy<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>>
399-
= Lazy::new(stdout_init);
400+
= unsafe { Lazy::new(stdout_init) };
400401
return Stdout {
401402
inner: INSTANCE.get().expect("cannot access stdout during shutdown"),
402403
};
403404

404405
fn stdout_init() -> Arc<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>> {
406+
// This must not reentrantly access `INSTANCE`
405407
let stdout = match stdout_raw() {
406408
Ok(stdout) => Maybe::Real(stdout),
407409
_ => Maybe::Fake,
@@ -531,12 +533,14 @@ pub struct StderrLock<'a> {
531533
/// ```
532534
#[stable(feature = "rust1", since = "1.0.0")]
533535
pub fn stderr() -> Stderr {
534-
static INSTANCE: Lazy<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> = Lazy::new(stderr_init);
536+
static INSTANCE: Lazy<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> =
537+
unsafe { Lazy::new(stderr_init) };
535538
return Stderr {
536539
inner: INSTANCE.get().expect("cannot access stderr during shutdown"),
537540
};
538541

539542
fn stderr_init() -> Arc<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> {
543+
// This must not reentrantly access `INSTANCE`
540544
let stderr = match stderr_raw() {
541545
Ok(stderr) => Maybe::Real(stderr),
542546
_ => Maybe::Fake,

0 commit comments

Comments
 (0)