make Lazy::new unsafe and check reentrancy condition in the callers
This commit is contained in:
parent
819645bfc4
commit
22457deef7
2 changed files with 11 additions and 5 deletions
|
|
@ -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())));
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue