diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index a11dc39..72ab523 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1,92 +1,60 @@ name: CI on: pull_request: - push: # bors - branches: - - staging - - trying + merge_group: env: - CI: 1 - CARGO_INCREMENTAL: 0 - CARGO_PROFILE_DEV_DEBUG: false - CARGO_PROFILE_RELEASE_DEBUG: false RUSTFLAGS: -D warnings -W unreachable-pub - MIRIFLAGS: -Zmiri-check-number-validity -Zmiri-symbolic-alignment-check -Zmiri-tag-raw-pointers + MIRIFLAGS: -Zmiri-strict-provenance -Zmiri-symbolic-alignment-check jobs: cargo-test: name: Tests - if: ${{ github.event.pusher.name == 'bors[bot]' }} runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Install toolchain - uses: actions-rs/toolchain@v1 - with: - toolchain: 1.59.0 - profile: minimal - override: true + uses: dtolnay/rust-toolchain@1.84 - name: Enable caching - uses: Swatinem/rust-cache@v1.3.0 + uses: Swatinem/rust-cache@v2 - name: Compile - uses: actions-rs/cargo@v1 - with: - command: test - args: --all --all-targets --examples --no-run + run: cargo test --all --all-targets --examples --no-run - name: Run tests - uses: actions-rs/cargo@v1 - with: - command: test - args: --all --all-targets --examples + run: cargo test --all --all-targets --examples cargo-test-msrv: - name: Tests (1.41.0) + name: Tests (1.80.0) runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Install arbitrary nightly toolchain - uses: actions-rs/toolchain@v1 + uses: dtolnay/rust-toolchain@master with: - toolchain: nightly-2022-01-01 - profile: minimal + toolchain: nightly-2025-01-01 - name: Install msrv toolchain - uses: actions-rs/toolchain@v1 - with: - toolchain: 1.41.0 - profile: minimal - override: true + uses: dtolnay/rust-toolchain@1.80 - name: Generate minimal-versions lockfile - uses: actions-rs/cargo@v1 - with: - command: +nightly-2022-01-01 - args: -Z minimal-versions generate-lockfile + run: cargo +nightly-2025-01-01 -Zminimal-versions generate-lockfile - name: Enable caching - uses: Swatinem/rust-cache@v1.3.0 + uses: Swatinem/rust-cache@v2 - name: Compile - uses: actions-rs/cargo@v1 - with: - command: test - args: --locked --all --all-targets --examples --no-run + run: cargo test --locked --all --all-targets --examples --no-run - name: Run tests - uses: actions-rs/cargo@v1 - with: - command: test - args: --locked --all --all-targets --examples + run: cargo test --locked --all --all-targets --examples cargo-fmt: name: Formatting @@ -94,21 +62,15 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - - name: Instal toolchain - uses: actions-rs/toolchain@v1 + - name: Install toolchain + uses: dtolnay/rust-toolchain@1.84 with: - profile: minimal - toolchain: 1.59.0 - override: true components: rustfmt - name: Check formatting - uses: actions-rs/cargo@v1 - with: - command: fmt - args: --all -- --check + run: cargo fmt --all -- --check cargo-clippy: name: Lints @@ -118,19 +80,13 @@ jobs: - name: Checkout repository uses: actions/checkout@v2 - - name: Install beta toolchain - uses: actions-rs/toolchain@v1 + - name: Install toolchain + uses: dtolnay/rust-toolchain@1.84 with: - profile: minimal - toolchain: 1.59.0 - override: true components: clippy - - name: Check style - uses: actions-rs/cargo@v1 - with: - command: clippy - args: --all --all-targets + - name: Check clippy + run: cargo clippy --all --all-targets cargo-miri: name: Miri @@ -138,27 +94,18 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Install nightly toolchain - uses: actions-rs/toolchain@v1 + uses: dtolnay/rust-toolchain@nightly with: - profile: minimal - toolchain: nightly - override: true components: miri - name: Enable caching - uses: Swatinem/rust-cache@v1.3.0 + uses: Swatinem/rust-cache@v2 - name: Miri setup - uses: actions-rs/cargo@v1 - with: - command: miri - args: setup + run: cargo miri setup - name: Miri test - uses: actions-rs/cargo@v1 - with: - command: miri - args: test --workspace --all-features + run: cargo miri test --workspace --all-features diff --git a/Cargo.lock b/Cargo.lock index e8146ce..1dabe18 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "autocfg" @@ -17,19 +17,19 @@ checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" [[package]] name = "erasable" version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f11890ce181d47a64e5d1eb4b6caba0e7bae911a356723740d058a5d0340b7d" dependencies = [ "autocfg", - "either", "scopeguard", ] [[package]] name = "erasable" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f11890ce181d47a64e5d1eb4b6caba0e7bae911a356723740d058a5d0340b7d" +version = "1.3.0" dependencies = [ "autocfg", + "either", "scopeguard", ] @@ -41,10 +41,10 @@ checksum = "0744126afe1a6dd7f394cb50a716dbe086cb06e255e53d8d0185d82828358fb5" [[package]] name = "ptr-union" -version = "2.2.2" +version = "2.3.0" dependencies = [ "autocfg", - "erasable 1.2.1", + "erasable 1.3.0", "paste", ] @@ -53,15 +53,15 @@ name = "rc-borrow" version = "1.4.0" dependencies = [ "autocfg", - "erasable 1.2.1", + "erasable 1.3.0", ] [[package]] name = "rc-box" -version = "1.2.0" +version = "1.3.0" dependencies = [ - "erasable 1.2.1", - "slice-dst 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "erasable 1.3.0", + "slice-dst 1.5.1", "unsize", ] @@ -74,6 +74,8 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "slice-dst" version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec1a6721a6d7c2997cea654e3eda6a827432c5dd0a0ed923ddd9b1d691203412" dependencies = [ "autocfg", "erasable 1.2.1", @@ -81,12 +83,10 @@ dependencies = [ [[package]] name = "slice-dst" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec1a6721a6d7c2997cea654e3eda6a827432c5dd0a0ed923ddd9b1d691203412" +version = "1.6.0" dependencies = [ "autocfg", - "erasable 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "erasable 1.3.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index d00fb5c..44cca34 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,5 @@ [workspace] +resolver = "2" members = [ "crates/erasable", "crates/ptr-union", diff --git a/crates/erasable/Cargo.toml b/crates/erasable/Cargo.toml index b393f51..ecf26bd 100644 --- a/crates/erasable/Cargo.toml +++ b/crates/erasable/Cargo.toml @@ -1,14 +1,14 @@ [package] name = "erasable" -version = "1.2.1" -edition = "2018" +version = "1.3.0" +edition = "2021" +rust-version = "1.80" -authors = ["Christopher Durham (cad97) "] description = "Type-erased thin pointers." repository = "https://github.com/CAD97/pointer-utils/tree/master/crates/erasable" readme = "README.md" -keywords = ["thin","pointer","type","erasure"] -categories = ["data-structures","no-std","rust-patterns"] +keywords = ["thin", "pointer", "type", "erasure"] +categories = ["data-structures", "no-std", "rust-patterns"] license = "MIT OR Apache-2.0" [package.metadata.workspaces] diff --git a/crates/erasable/build.rs b/crates/erasable/build.rs index 5ed6fe8..02f0eef 100644 --- a/crates/erasable/build.rs +++ b/crates/erasable/build.rs @@ -1,11 +1,11 @@ use std::env; fn main() { + println!("cargo:rustc-check-cfg=cfg(has_extern_type, has_never, enforce_1_1_0_semantics)"); + let cfg = autocfg::new(); cfg.emit_expression_cfg("{ extern { type T; } () }", "has_extern_type"); - // NB: Requires this impl to cover `T: ?Sized`, which is not the case as of 2020-09-01. - // cfg.emit_type_cfg("std::sync::Weak::into_raw", "has_Weak__into_raw"); cfg.emit_type_cfg("!", "has_never"); if let Ok(var) = env::var("ERASABLE_ENFORCE_1_1_0_SEMANTICS") { diff --git a/crates/erasable/src/lib.rs b/crates/erasable/src/lib.rs index 8b15078..c4ef4bd 100644 --- a/crates/erasable/src/lib.rs +++ b/crates/erasable/src/lib.rs @@ -720,13 +720,11 @@ macro_rules! impl_erasable { } #[cfg(feature = "alloc")] -impl_erasable!(for - Box, +impl_erasable!( + for Box, sync::Arc, - #[cfg(has_Weak__into_raw)] sync::Weak, rc::Rc, - #[cfg(has_Weak__into_raw)] rc::Weak, ); @@ -749,11 +747,13 @@ unsafe impl ErasablePtr for ! { } #[inline(always)] +#[allow(clippy::needless_lifetimes)] unsafe fn erase_lt<'a, 'b, T: ?Sized>(this: &'a T) -> &'b T { &*(this as *const T) } #[inline(always)] +#[allow(clippy::needless_lifetimes)] unsafe fn erase_lt_mut<'a, 'b, T: ?Sized>(this: &'a mut T) -> &'b mut T { &mut *(this as *mut T) } diff --git a/crates/erasable/tests/smoke.rs b/crates/erasable/tests/smoke.rs index 6452a08..6f2fd9d 100644 --- a/crates/erasable/tests/smoke.rs +++ b/crates/erasable/tests/smoke.rs @@ -1,7 +1,7 @@ //! These tests don't really assert anything, they just exercise the API. //! This is primarily intended to be run under miri as a sanitizer. -#![allow(unused, clippy::redundant_clone, clippy::unnecessary_operation)] +#![allow(unused, clippy::style)] use erasable::{Erasable, ErasablePtr, ErasedPtr, Thin}; diff --git a/crates/ptr-union/Cargo.toml b/crates/ptr-union/Cargo.toml index 9b1eb61..48bb416 100644 --- a/crates/ptr-union/Cargo.toml +++ b/crates/ptr-union/Cargo.toml @@ -1,14 +1,13 @@ [package] name = "ptr-union" -version = "2.2.2" -edition = "2018" +version = "2.3.0" +edition = "2021" -authors = ["Christopher Durham (cad97) "] description = "Pointer union types the size of a pointer by storing the tag in the alignment bits." repository = "https://github.com/CAD97/pointer-utils/tree/master/crates/ptr-union" readme = "README.md" -keywords = ["thin","pointer","union","enum"] -categories = ["data-structures","no-std","rust-patterns"] +keywords = ["thin", "pointer", "union", "enum"] +categories = ["data-structures", "no-std", "rust-patterns"] license = "MIT OR Apache-2.0" [package.metadata.workspaces] diff --git a/crates/ptr-union/build.rs b/crates/ptr-union/build.rs index f689276..ae1cc81 100644 --- a/crates/ptr-union/build.rs +++ b/crates/ptr-union/build.rs @@ -1,5 +1,7 @@ fn main() { let cfg = autocfg::new(); + println!("cargo::rustc-check-cfg=cfg(has_never, has_strict_provenance)"); cfg.emit_type_cfg("!", "has_never"); + cfg.emit_expression_cfg("<*const ()>::addr", "has_strict_provenance"); autocfg::rerun_path("build.rs"); } diff --git a/crates/ptr-union/src/lib.rs b/crates/ptr-union/src/lib.rs index 494bb70..d23b489 100644 --- a/crates/ptr-union/src/lib.rs +++ b/crates/ptr-union/src/lib.rs @@ -38,12 +38,18 @@ const TAG_N: usize = 0b1101; const TAG_O: usize = 0b1110; const TAG_P: usize = 0b1111; -// See rust-lang/rust#95228 for why these are necessary. fn ptr_addr(this: *mut T) -> usize { - // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. - this as usize + #[cfg(not(has_strict_provenance))] + { + this as usize + } + #[cfg(has_strict_provenance)] + { + this.addr() + } } +#[cfg(not(has_strict_provenance))] fn ptr_with_addr(this: *mut T, addr: usize) -> *mut T { // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. // @@ -59,7 +65,14 @@ fn ptr_with_addr(this: *mut T, addr: usize) -> *mut T { } fn ptr_map_addr(this: *mut T, f: impl FnOnce(usize) -> usize) -> *mut T { - ptr_with_addr(this, f(ptr_addr(this))) + #[cfg(not(has_strict_provenance))] + { + ptr_with_addr(this, f(ptr_addr(this))) + } + #[cfg(has_strict_provenance)] + { + this.map_addr(f) + } } fn ptr_tag(this: *mut T, tag: usize) -> *mut T { @@ -684,6 +697,7 @@ impl fmt::Debug } } +#[allow(clippy::needless_lifetimes)] unsafe fn erase_lt<'a, 'b, T: ?Sized>(r: &'a T) -> &'b T { &*(r as *const T) } diff --git a/crates/ptr-union/tests/clone_unaligned.rs b/crates/ptr-union/tests/clone_unaligned.rs index aee6667..002f53a 100644 --- a/crates/ptr-union/tests/clone_unaligned.rs +++ b/crates/ptr-union/tests/clone_unaligned.rs @@ -12,6 +12,17 @@ struct MyBox { ptr: NonNull, } +fn ptr_dangling_at(addr: usize) -> *mut T { + #[cfg(not(has_strict_provenance))] + { + addr as _ + } + #[cfg(has_strict_provenance)] + { + std::ptr::without_provenance_mut(addr) + } +} + // SAFETY: // * MyBox doesn't have any shared mutability // * the address of the returned pointer doesn't depend on the address of MyBox @@ -32,7 +43,7 @@ impl MyBox { fn new() -> Self { let offset = OFFSET.fetch_add(1, std::sync::atomic::Ordering::SeqCst); MyBox { - ptr: NonNull::new(offset as _).unwrap(), + ptr: NonNull::new(ptr_dangling_at(offset)).unwrap(), } } } diff --git a/crates/ptr-union/tests/smoke.rs b/crates/ptr-union/tests/smoke.rs index f125fcc..7f5a4c1 100644 --- a/crates/ptr-union/tests/smoke.rs +++ b/crates/ptr-union/tests/smoke.rs @@ -1,7 +1,7 @@ //! These tests don't really assert anything, they just exercise the API. //! This is primarily intended to be run under miri as a sanitizer. -#![allow(clippy::borrowed_box, clippy::drop_ref)] +#![allow(unused, dropping_references, clippy::borrowed_box)] use ptr_union::{Builder2, Builder4}; diff --git a/crates/rc-borrow/Cargo.toml b/crates/rc-borrow/Cargo.toml index daaa9c6..7ca05ff 100644 --- a/crates/rc-borrow/Cargo.toml +++ b/crates/rc-borrow/Cargo.toml @@ -3,12 +3,11 @@ name = "rc-borrow" version = "1.4.0" edition = "2018" -authors = ["Christopher Durham (cad97) "] description = "Borrowed forms of Rc and Arc." repository = "https://github.com/CAD97/pointer-utils/tree/master/crates/rc-borrow" readme = "README.md" -keywords = ["rc","arc","borrow","reference"] -categories = ["data-structures","no-std","rust-patterns"] +keywords = ["rc", "arc", "borrow", "reference"] +categories = ["data-structures", "no-std", "rust-patterns"] license = "MIT OR Apache-2.0" [package.metadata.workspaces] diff --git a/crates/rc-borrow/src/lib.rs b/crates/rc-borrow/src/lib.rs index 9d0a860..9c55d7c 100644 --- a/crates/rc-borrow/src/lib.rs +++ b/crates/rc-borrow/src/lib.rs @@ -183,6 +183,8 @@ macro_rules! rc_borrow { concat!("\ Construct a new `", stringify!($RcBorrow), "` from a raw pointer. +# Safety + The raw pointer must have been previously returned by a call to `",stringify!($RcBorrow),"::into_raw` or `",stringify!($Rc),"::as_raw` where `U` must have the same size and alignment as `T`. This is trivially true diff --git a/crates/rc-box/Cargo.toml b/crates/rc-box/Cargo.toml index 904a55d..1b8a04a 100644 --- a/crates/rc-box/Cargo.toml +++ b/crates/rc-box/Cargo.toml @@ -1,14 +1,14 @@ [package] name = "rc-box" -version = "1.2.0" -edition = "2018" +version = "1.3.0" +edition = "2021" authors = ["Christopher Durham (cad97) "] description = "Known unique versions of Rc and Arc." repository = "https://github.com/CAD97/pointer-utils/tree/master/crates/rc-box" readme = "README.md" -keywords = ["rc","arc","unique","box"] -categories = ["data-structures","no-std","rust-patterns"] +keywords = ["rc", "arc", "unique", "box"] +categories = ["data-structures", "no-std", "rust-patterns"] license = "MIT OR Apache-2.0" [package.metadata.workspaces] @@ -19,6 +19,7 @@ maintenance = { status = "passively-maintained" } [features] default = ["erasable"] +std = [] [dependencies] slice-dst = { version = "1.4.0", optional = true } diff --git a/crates/slice-dst/Cargo.toml b/crates/slice-dst/Cargo.toml index e0a1d15..4ce7c42 100644 --- a/crates/slice-dst/Cargo.toml +++ b/crates/slice-dst/Cargo.toml @@ -1,14 +1,13 @@ [package] name = "slice-dst" -version = "1.5.1" -edition = "2018" +version = "1.6.0" +edition = "2021" -authors = ["Christopher Durham (cad97) "] description = "Slice-based custom DSTs" repository = "https://github.com/CAD97/pointer-utils/tree/master/crates/slice-dst" readme = "README.md" -keywords = ["thin","slice","type","erasure","dst"] -categories = ["data-structures","no-std","rust-patterns"] +keywords = ["thin", "slice", "type", "erasure", "dst"] +categories = ["data-structures", "no-std", "rust-patterns"] license = "MIT OR Apache-2.0" [package.metadata.workspaces] diff --git a/crates/slice-dst/build.rs b/crates/slice-dst/build.rs index d98d4ce..569b959 100644 --- a/crates/slice-dst/build.rs +++ b/crates/slice-dst/build.rs @@ -1,9 +1,7 @@ fn main() { let cfg = autocfg::new(); - cfg.emit_expression_cfg( - "std::ptr::slice_from_raw_parts_mut::<()>", - "has_ptr_slice_from_raw_parts", - ); - + println!("cargo::rustc-check-cfg=cfg(has_strict_provenance)"); + cfg.emit_type_cfg("!", "has_never"); + cfg.emit_expression_cfg("<*const ()>::addr", "has_strict_provenance"); autocfg::rerun_path("build.rs"); } diff --git a/crates/slice-dst/src/layout_polyfill.rs b/crates/slice-dst/src/layout_polyfill.rs deleted file mode 100644 index e23f398..0000000 --- a/crates/slice-dst/src/layout_polyfill.rs +++ /dev/null @@ -1,64 +0,0 @@ -#![allow(deprecated)] // this is a polyfill module - -use core::{ - alloc::{Layout, LayoutErr}, - cmp, -}; - -#[inline] -pub(crate) fn extend_layout(this: &Layout, next: Layout) -> Result<(Layout, usize), LayoutErr> { - let new_align = cmp::max(this.align(), next.align()); - let pad = layout_padding_needed_for(this, next.align()); - let offset = this.size().checked_add(pad).ok_or_else(layout_err)?; - let new_size = offset.checked_add(next.size()).ok_or_else(layout_err)?; - let layout = Layout::from_size_align(new_size, new_align)?; - Ok((layout, offset)) -} - -#[inline] -pub(crate) fn pad_layout_to_align(this: &Layout) -> Layout { - let pad = layout_padding_needed_for(this, this.align()); - let new_size = this.size() + pad; - unsafe { Layout::from_size_align_unchecked(new_size, this.align()) } -} - -#[inline] -pub(crate) fn layout_array(n: usize) -> Result { - repeat_layout(&Layout::new::(), n).map(|(k, _)| k) -} - -#[inline] -pub(crate) fn repr_c_3(fields: [Layout; 3]) -> Result<(Layout, [usize; 3]), LayoutErr> { - let mut offsets: [usize; 3] = [0; 3]; - let mut layout = fields[0]; - for i in 1..3 { - let (new_layout, this_offset) = extend_layout(&layout, fields[i])?; - layout = new_layout; - offsets[i] = this_offset; - } - Ok((pad_layout_to_align(&layout), offsets)) -} - -#[inline] -fn layout_padding_needed_for(this: &Layout, align: usize) -> usize { - let len = this.size(); - let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1); - len_rounded_up.wrapping_sub(len) -} - -#[inline] -fn repeat_layout(this: &Layout, n: usize) -> Result<(Layout, usize), LayoutErr> { - let padded_size = pad_layout_to_align(this).size(); - let alloc_size = padded_size.checked_mul(n).ok_or_else(layout_err)?; - unsafe { - Ok(( - Layout::from_size_align_unchecked(alloc_size, this.align()), - padded_size, - )) - } -} - -#[inline] -fn layout_err() -> LayoutErr { - Layout::from_size_align(0, 0).unwrap_err() -} diff --git a/crates/slice-dst/src/lib.rs b/crates/slice-dst/src/lib.rs index d6d4444..50d0fd8 100644 --- a/crates/slice-dst/src/lib.rs +++ b/crates/slice-dst/src/lib.rs @@ -87,7 +87,7 @@ //! - [Array layout][array-layout] and [slice layout][slice-layout] are defined. //! - [`#[repr(C)]`][repr-c-layout] allows us to make compound types with defined layout. //! - We can turn an opaque pointer into a slice fat pointer with -//! [`ptr::slice_from_raw_parts`][slice_from_raw_parts]. +//! [`ptr::slice_from_raw_parts`]. //! - We can cast a slice pointer to a pointer to our compound type //! in order to keep the correct fat pointer metadata. //! @@ -138,10 +138,6 @@ extern crate alloc; -#[cfg(has_ptr_slice_from_raw_parts)] -use core::ptr::slice_from_raw_parts_mut as slice_from_raw_parts; -#[cfg(not(has_ptr_slice_from_raw_parts))] -use core::slice::from_raw_parts_mut as slice_from_raw_parts; #[cfg(feature = "erasable")] use erasable::{Erasable, ErasedPtr}; use { @@ -186,7 +182,7 @@ pub unsafe trait SliceDst { unsafe impl SliceDst for [T] { fn layout_for(len: usize) -> Layout { - layout_polyfill::layout_array::(len).unwrap() + Layout::array::(len).unwrap() } fn retype(ptr: ptr::NonNull<[()]>) -> ptr::NonNull { @@ -224,12 +220,12 @@ where unsafe { let ptr = if layout.size() == 0 { // Do not allocate in the ZST case! CAD97/pointer-utils#23 - ptr::NonNull::new(layout.align() as *mut ()) + ptr::NonNull::new(polyfill::ptr_dangling_at(layout.align())) } else { ptr::NonNull::new(alloc(layout) as *mut ()) } .unwrap_or_else(|| handle_alloc_error(layout)); - let ptr = ptr::NonNull::new_unchecked(slice_from_raw_parts(ptr.as_ptr(), len)); + let ptr = ptr::NonNull::new_unchecked(ptr::slice_from_raw_parts_mut(ptr.as_ptr(), len)); S::retype(ptr) } } @@ -383,7 +379,7 @@ unsafe impl TryAllocSliceDst for Arc { } } -pub(crate) mod layout_polyfill; +pub(crate) mod polyfill; mod provided_types; pub use provided_types::{SliceWithHeader, StrWithHeader}; diff --git a/crates/slice-dst/src/polyfill.rs b/crates/slice-dst/src/polyfill.rs new file mode 100644 index 0000000..15c43e5 --- /dev/null +++ b/crates/slice-dst/src/polyfill.rs @@ -0,0 +1,40 @@ +// #![allow(deprecated)] // this is a polyfill module + +use core::alloc::{Layout, LayoutError}; + +#[inline] +pub(crate) fn pad_layout_to_align(this: &Layout) -> Layout { + let pad = layout_padding_needed_for(this, this.align()); + let new_size = this.size() + pad; + unsafe { Layout::from_size_align_unchecked(new_size, this.align()) } +} + +#[inline] +pub(crate) fn repr_c_3(fields: [Layout; 3]) -> Result<(Layout, [usize; 3]), LayoutError> { + let mut offsets: [usize; 3] = [0; 3]; + let mut layout = fields[0]; + for i in 1..3 { + let (new_layout, this_offset) = layout.extend(fields[i])?; + layout = new_layout; + offsets[i] = this_offset; + } + Ok((pad_layout_to_align(&layout), offsets)) +} + +#[inline] +fn layout_padding_needed_for(this: &Layout, align: usize) -> usize { + let len = this.size(); + let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1); + len_rounded_up.wrapping_sub(len) +} + +pub(crate) fn ptr_dangling_at(addr: usize) -> *mut T { + #[cfg(not(has_strict_provenance))] + { + addr as _ + } + #[cfg(has_strict_provenance)] + { + core::ptr::without_provenance_mut(addr) + } +} diff --git a/crates/slice-dst/src/provided_types.rs b/crates/slice-dst/src/provided_types.rs index 87b87b5..d8e5575 100644 --- a/crates/slice-dst/src/provided_types.rs +++ b/crates/slice-dst/src/provided_types.rs @@ -29,8 +29,8 @@ impl SliceWithHeader { fn layout(len: usize) -> (Layout, [usize; 3]) { let length_layout = Layout::new::(); let header_layout = Layout::new::
(); - let slice_layout = layout_polyfill::layout_array::(len).unwrap(); - layout_polyfill::repr_c_3([length_layout, header_layout, slice_layout]).unwrap() + let slice_layout = Layout::array::(len).unwrap(); + polyfill::repr_c_3([length_layout, header_layout, slice_layout]).unwrap() } #[allow(clippy::new_ret_no_self)] @@ -60,7 +60,7 @@ impl SliceWithHeader { impl Drop for InProgress { fn drop(&mut self) { unsafe { - ptr::drop_in_place(slice_from_raw_parts( + ptr::drop_in_place(ptr::slice_from_raw_parts_mut( self.raw().add(self.slice_offset).cast::(), self.written, )); @@ -72,7 +72,7 @@ impl SliceWithHeader { fn init( len: usize, header: Header, - mut items: impl Iterator + ExactSizeIterator, + mut items: impl ExactSizeIterator, ) -> impl FnOnce(ptr::NonNull>) { move |ptr| { let mut this = Self::new(len, ptr); @@ -167,7 +167,8 @@ where unsafe impl Erasable for SliceWithHeader { unsafe fn unerase(this: ErasedPtr) -> ptr::NonNull { let len: usize = ptr::read(this.as_ptr().cast()); - let raw = ptr::NonNull::new_unchecked(slice_from_raw_parts(this.as_ptr().cast(), len)); + let raw = + ptr::NonNull::new_unchecked(ptr::slice_from_raw_parts_mut(this.as_ptr().cast(), len)); Self::retype(raw) } @@ -203,8 +204,8 @@ impl
StrWithHeader
{ fn layout(len: usize) -> (Layout, [usize; 3]) { let length_layout = Layout::new::(); let header_layout = Layout::new::
(); - let slice_layout = layout_polyfill::layout_array::(len).unwrap(); - layout_polyfill::repr_c_3([length_layout, header_layout, slice_layout]).unwrap() + let slice_layout = Layout::array::(len).unwrap(); + polyfill::repr_c_3([length_layout, header_layout, slice_layout]).unwrap() } #[allow(clippy::new_ret_no_self)] @@ -240,7 +241,8 @@ where unsafe impl
Erasable for StrWithHeader
{ unsafe fn unerase(this: ErasedPtr) -> ptr::NonNull { let len: usize = ptr::read(this.as_ptr().cast()); - let raw = ptr::NonNull::new_unchecked(slice_from_raw_parts(this.as_ptr().cast(), len)); + let raw = + ptr::NonNull::new_unchecked(ptr::slice_from_raw_parts_mut(this.as_ptr().cast(), len)); Self::retype(raw) } diff --git a/crates/slice-dst/tests/leak.rs b/crates/slice-dst/tests/leak.rs index fca52bb..3e6b3cd 100644 --- a/crates/slice-dst/tests/leak.rs +++ b/crates/slice-dst/tests/leak.rs @@ -29,10 +29,6 @@ impl Drop for DropTracking<'_> { } #[test] -#[cfg_attr( - all(miri, target_os = "windows"), - ignore = "miri does not support panicking on windows rust-lang/miri#1059" -)] fn bad_exactsizeiterator() { struct Iter<'a> { counter: &'a AtomicUsize, @@ -72,6 +68,7 @@ fn bad_exactsizeiterator() { assert_eq!(*counter.get_mut(), 0); } +#[allow(dead_code)] struct S(u8); unsafe impl SliceDst for S { @@ -85,10 +82,6 @@ unsafe impl SliceDst for S { } #[test] -#[cfg_attr( - all(miri, target_os = "windows"), - ignore = "miri does not support panicking on windows rust-lang/miri#1059" -)] fn panic_in_init() { // This relies on miri to catch leaks let _ = std::panic::catch_unwind(|| { diff --git a/crates/slice-dst/tests/smoke.rs b/crates/slice-dst/tests/smoke.rs index 71b79b3..6efe094 100644 --- a/crates/slice-dst/tests/smoke.rs +++ b/crates/slice-dst/tests/smoke.rs @@ -1,7 +1,7 @@ //! These tests don't really assert anything, they just exercise the API. //! This is primarily intended to be run under miri as a sanitizer. -#![allow(unused, clippy::redundant_clone)] +#![allow(unused, clippy::style)] use { erasable::Thin,