-
Notifications
You must be signed in to change notification settings - Fork 105
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix soundness hole in Ref::into_ref and into_mut (#721)
This commit implements the fix for #716 which will be released as a new version in version trains 0.2, 0.3, 0.4, 0.5, 0.6, and 0.7. See #716 for a description of the soundness hole and an explanation of why this fix is chosen. Unfortunately, due to dtolnay/trybuild#241, there is no way for us to write a UI test that will detect a failure post-monomorphization, which is when the code implemented in this change is designed to fail. I have manually verified that unsound uses of these APIs now fail to compile. Release 0.7.31.
- Loading branch information
Showing
4 changed files
with
201 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
// Copyright 2018 The Fuchsia Authors | ||
// | ||
// Licensed under the 2-Clause BSD License <LICENSE-BSD or | ||
// https://opensource.org/license/bsd-2-clause>, Apache License, Version 2.0 | ||
// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT | ||
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option. | ||
// This file may not be copied, modified, or distributed except according to | ||
// those terms. | ||
|
||
//! Code that should fail to compile during the post-monomorphization compiler | ||
//! pass. | ||
//! | ||
//! Due to [a limitation with the `trybuild` crate][trybuild-issue], we cannot | ||
//! use our UI testing framework to test compilation failures that are | ||
//! encountered after monomorphization has complated. This module has one item | ||
//! for each such test we would prefer to have as a UI test, with the code in | ||
//! question appearing as a rustdoc example which is marked with `compile_fail`. | ||
//! This has the effect of causing doctests to fail if any of these examples | ||
//! compile successfully. | ||
//! | ||
//! This is very much a hack and not a complete replacement for UI tests - most | ||
//! notably because this only provides a single "compile vs fail" bit of | ||
//! information, but does not allow us to depend upon the specific error that | ||
//! causes compilation to fail. | ||
//! | ||
//! [trybuild-issue]: https://github.com/dtolnay/trybuild/issues/241 | ||
|
||
// Miri doesn't detect post-monimorphization failures as compile-time failures, | ||
// but instead as runtime failures. | ||
#![cfg(not(miri))] | ||
|
||
/// ```compile_fail | ||
/// use core::cell::{Ref, RefCell}; | ||
/// | ||
/// let refcell = RefCell::new([0u8, 1, 2, 3]); | ||
/// let core_ref = refcell.borrow(); | ||
/// let core_ref = Ref::map(core_ref, |bytes| &bytes[..]); | ||
/// | ||
/// // `zc_ref` now stores `core_ref` internally. | ||
/// let zc_ref = zerocopy::Ref::<_, u32>::new(core_ref).unwrap(); | ||
/// | ||
/// // This causes `core_ref` to get dropped and synthesizes a Rust | ||
/// // reference to the memory `core_ref` was pointing at. | ||
/// let rust_ref = zc_ref.into_ref(); | ||
/// | ||
/// // UB!!! This mutates `rust_ref`'s referent while it's alive. | ||
/// *refcell.borrow_mut() = [0, 0, 0, 0]; | ||
/// | ||
/// println!("{}", rust_ref); | ||
/// ``` | ||
#[allow(unused)] | ||
const REFCELL_REF_INTO_REF: () = (); | ||
|
||
/// ```compile_fail | ||
/// use core::cell::{RefCell, RefMut}; | ||
/// | ||
/// let refcell = RefCell::new([0u8, 1, 2, 3]); | ||
/// let core_ref_mut = refcell.borrow_mut(); | ||
/// let core_ref_mut = RefMut::map(core_ref_mut, |bytes| &mut bytes[..]); | ||
/// | ||
/// // `zc_ref` now stores `core_ref_mut` internally. | ||
/// let zc_ref = zerocopy::Ref::<_, u32>::new(core_ref_mut).unwrap(); | ||
/// | ||
/// // This causes `core_ref_mut` to get dropped and synthesizes a Rust | ||
/// // reference to the memory `core_ref` was pointing at. | ||
/// let rust_ref_mut = zc_ref.into_mut(); | ||
/// | ||
/// // UB!!! This mutates `rust_ref_mut`'s referent while it's alive. | ||
/// *refcell.borrow_mut() = [0, 0, 0, 0]; | ||
/// | ||
/// println!("{}", rust_ref_mut); | ||
/// ``` | ||
#[allow(unused)] | ||
const REFCELL_REFMUT_INTO_MUT: () = (); | ||
|
||
/// ```compile_fail | ||
/// use core::cell::{Ref, RefCell}; | ||
/// | ||
/// let refcell = RefCell::new([0u8, 1, 2, 3]); | ||
/// let core_ref = refcell.borrow(); | ||
/// let core_ref = Ref::map(core_ref, |bytes| &bytes[..]); | ||
/// | ||
/// // `zc_ref` now stores `core_ref` internally. | ||
/// let zc_ref = zerocopy::Ref::<_, [u16]>::new_slice(core_ref).unwrap(); | ||
/// | ||
/// // This causes `core_ref` to get dropped and synthesizes a Rust | ||
/// // reference to the memory `core_ref` was pointing at. | ||
/// let rust_ref = zc_ref.into_slice(); | ||
/// | ||
/// // UB!!! This mutates `rust_ref`'s referent while it's alive. | ||
/// *refcell.borrow_mut() = [0, 0, 0, 0]; | ||
/// | ||
/// println!("{:?}", rust_ref); | ||
/// ``` | ||
#[allow(unused)] | ||
const REFCELL_REFMUT_INTO_SLICE: () = (); | ||
|
||
/// ```compile_fail | ||
/// use core::cell::{RefCell, RefMut}; | ||
/// | ||
/// let refcell = RefCell::new([0u8, 1, 2, 3]); | ||
/// let core_ref_mut = refcell.borrow_mut(); | ||
/// let core_ref_mut = RefMut::map(core_ref_mut, |bytes| &mut bytes[..]); | ||
/// | ||
/// // `zc_ref` now stores `core_ref_mut` internally. | ||
/// let zc_ref = zerocopy::Ref::<_, [u16]>::new_slice(core_ref_mut).unwrap(); | ||
/// | ||
/// // This causes `core_ref_mut` to get dropped and synthesizes a Rust | ||
/// // reference to the memory `core_ref` was pointing at. | ||
/// let rust_ref_mut = zc_ref.into_mut_slice(); | ||
/// | ||
/// // UB!!! This mutates `rust_ref_mut`'s referent while it's alive. | ||
/// *refcell.borrow_mut() = [0, 0, 0, 0]; | ||
/// | ||
/// println!("{:?}", rust_ref_mut); | ||
/// ``` | ||
#[allow(unused)] | ||
const REFCELL_REFMUT_INTO_MUT_SLICE: () = (); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters