Skip to content

Commit cdf6323

Browse files
committed
Use associated constant to make Lazy's fields private.
This is to patch an obscure soundness hole. With the fields public, it is possible to for a consumer crate to access and call the std::sync::Once without assigning the correct value to the pointer in the tuple's first field, making it possible to later deref a null pointer from safe code. However now that lazy_static targets 1.21.0+, we can use an associated constant in the __lazy_static_create macro instead of requiring consumers to literally construct the inner values post-expansion. This is technically a breaking change, but given that any existing use of these inner fields is very likely to cause unsoundness I think it's consistent with Rust's semver policy to make this change and stay at 1.0.
1 parent 1a18c65 commit cdf6323

File tree

1 file changed

+7
-4
lines changed

1 file changed

+7
-4
lines changed

src/heap_lazy.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,15 @@ use self::std::prelude::v1::*;
1111
use self::std::sync::Once;
1212
pub use self::std::sync::ONCE_INIT;
1313

14-
pub struct Lazy<T: Sync>(pub *const T, pub Once);
14+
pub struct Lazy<T: Sync>(*const T, Once);
1515

1616
impl<T: Sync> Lazy<T> {
17+
pub const INIT: Self = Lazy(0 as *const T, ONCE_INIT);
18+
1719
#[inline(always)]
1820
pub fn get<F>(&'static mut self, f: F) -> &T
19-
where F: FnOnce() -> T
21+
where
22+
F: FnOnce() -> T,
2023
{
2124
unsafe {
2225
let r = &mut self.0;
@@ -35,6 +38,6 @@ unsafe impl<T: Sync> Sync for Lazy<T> {}
3538
#[doc(hidden)]
3639
macro_rules! __lazy_static_create {
3740
($NAME:ident, $T:ty) => {
38-
static mut $NAME: $crate::lazy::Lazy<$T> = $crate::lazy::Lazy(0 as *const $T, $crate::lazy::ONCE_INIT);
39-
}
41+
static mut $NAME: $crate::lazy::Lazy<$T> = $crate::lazy::Lazy::INIT;
42+
};
4043
}

0 commit comments

Comments
 (0)