225: A fix that stops panics from the old MaybeUninit impl r=korken89 a=korken89

Sometimes when running in debug mode the current implementation of `MaybeUninit` would panic, an example can be found here: 2bb89427fa/examples/rtfm-uarte-interrupts/src/main.rs (L106)
On debug this line will always panic, on release all is fine.

The issue seemed to be the manual `MaybeUninit` implementation, so I have merged the two implementations together.
Please have a look and see if my fix is unsound (it does however work, but not sure on UB).

cc @japaric @TeXitoi 

Co-authored-by: Emil Fresk <emil.fresk@gmail.com>
This commit is contained in:
bors[bot] 2019-10-23 20:28:50 +00:00 committed by GitHub
commit 34a2767bdf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 22 additions and 59 deletions

View file

@ -5,6 +5,11 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased] ## [Unreleased]
### Fixed
- Soundness issue in the `MaybeUninit` implementation
- Warning for deprecated `mem::uninitialized`
## [v0.4.3] - 2019-04-21 ## [v0.4.3] - 2019-04-21
### Changed ### Changed

View file

@ -41,7 +41,7 @@ A concurrency framework for building real time systems.
## Requirements ## Requirements
- Rust 1.31.0+ - Rust 1.36.0+
- Applications must be written using the 2018 edition. - Applications must be written using the 2018 edition.

View file

@ -39,7 +39,7 @@
## Требования ## Требования
- Rust 1.31.0+ - Rust 1.36.0+
- Программы нужно писать используя 2018 edition. - Программы нужно писать используя 2018 edition.

View file

@ -1948,13 +1948,13 @@ fn pre_init(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::Toke
// these are `MaybeUninit` arrays // these are `MaybeUninit` arrays
for task in ctxt.tasks.values() { for task in ctxt.tasks.values() {
let inputs = &task.inputs; let inputs = &task.inputs;
exprs.push(quote!(#inputs.write(core::mem::uninitialized());)) exprs.push(quote!(#inputs.write(core::mem::MaybeUninit::uninit());))
} }
#[cfg(feature = "timer-queue")] #[cfg(feature = "timer-queue")]
for task in ctxt.tasks.values() { for task in ctxt.tasks.values() {
let scheduleds = &task.scheduleds; let scheduleds = &task.scheduleds;
exprs.push(quote!(#scheduleds.write(core::mem::uninitialized());)) exprs.push(quote!(#scheduleds.write(core::mem::MaybeUninit::uninit());))
} }
// these are `MaybeUninit` `ReadyQueue`s // these are `MaybeUninit` `ReadyQueue`s

View file

@ -1,7 +1,5 @@
//! IMPLEMENTATION DETAILS. DO NOT USE ANYTHING IN THIS MODULE //! IMPLEMENTATION DETAILS. DO NOT USE ANYTHING IN THIS MODULE
#[cfg(not(feature = "nightly"))]
use core::ptr;
use core::{cell::Cell, u8}; use core::{cell::Cell, u8};
#[cfg(armv7m)] #[cfg(armv7m)]
@ -64,13 +62,11 @@ impl Priority {
} }
} }
#[cfg(feature = "nightly")]
pub struct MaybeUninit<T> { pub struct MaybeUninit<T> {
// we newtype so the end-user doesn't need `#![feature(maybe_uninit)]` in their code // we newtype so the end-user doesn't need `#![feature(maybe_uninit)]` in their code
inner: core::mem::MaybeUninit<T>, inner: core::mem::MaybeUninit<T>,
} }
#[cfg(feature = "nightly")]
impl<T> MaybeUninit<T> { impl<T> MaybeUninit<T> {
pub const fn uninit() -> Self { pub const fn uninit() -> Self {
MaybeUninit { MaybeUninit {
@ -86,61 +82,23 @@ impl<T> MaybeUninit<T> {
self.inner.as_mut_ptr() self.inner.as_mut_ptr()
} }
pub fn write(&mut self, value: T) -> &mut T {
self.inner.write(value)
}
}
#[cfg(not(feature = "nightly"))]
pub struct MaybeUninit<T> {
value: Option<T>,
}
#[cfg(not(feature = "nightly"))]
const MSG: &str =
"you have hit a bug (UB) in RTFM implementation; try enabling this crate 'nightly' feature";
#[cfg(not(feature = "nightly"))]
impl<T> MaybeUninit<T> {
pub const fn uninit() -> Self {
MaybeUninit { value: None }
}
pub fn as_ptr(&self) -> *const T {
if let Some(x) = self.value.as_ref() {
x
} else {
unreachable!(MSG)
}
}
pub fn as_mut_ptr(&mut self) -> *mut T {
if let Some(x) = self.value.as_mut() {
x
} else {
unreachable!(MSG)
}
}
pub unsafe fn get_ref(&self) -> &T { pub unsafe fn get_ref(&self) -> &T {
if let Some(x) = self.value.as_ref() { &*self.inner.as_ptr()
x
} else {
unreachable!(MSG)
}
} }
pub unsafe fn get_mut(&mut self) -> &mut T { pub unsafe fn get_mut(&mut self) -> &mut T {
if let Some(x) = self.value.as_mut() { &mut *self.inner.as_mut_ptr()
x
} else {
unreachable!(MSG)
}
} }
pub fn write(&mut self, val: T) { #[cfg(feature = "nightly")]
// NOTE(volatile) we have observed UB when this uses a plain `ptr::write` pub fn write(&mut self, value: T) -> &mut T {
unsafe { ptr::write_volatile(&mut self.value, Some(val)) } self.inner.write(value)
}
#[cfg(not(feature = "nightly"))]
pub fn write(&mut self, value: T) -> &mut T {
self.inner = core::mem::MaybeUninit::new(value);
unsafe { self.get_mut() }
} }
} }

View file

@ -16,7 +16,7 @@
//! //!
//! # Minimum Supported Rust Version (MSRV) //! # Minimum Supported Rust Version (MSRV)
//! //!
//! This crate is guaranteed to compile on stable Rust 1.31 (2018 edition) and up. It *might* //! This crate is guaranteed to compile on stable Rust 1.36 (2018 edition) and up. It *might*
//! compile on older versions but that may change in any new patch release. //! compile on older versions but that may change in any new patch release.
//! //!
//! # Semantic Versioning //! # Semantic Versioning
@ -41,7 +41,7 @@
//! usage, runtime overhead and initialization overhead. This feature requires a nightly compiler //! usage, runtime overhead and initialization overhead. This feature requires a nightly compiler
//! and may stop working at any time! //! and may stop working at any time!
#![cfg_attr(feature = "nightly", feature(maybe_uninit))] #![cfg_attr(feature = "nightly", feature(maybe_uninit_extra))]
#![deny(missing_docs)] #![deny(missing_docs)]
#![deny(warnings)] #![deny(warnings)]
#![no_std] #![no_std]