diff options
Diffstat (limited to 'src/test/ui/intrinsics/panic-uninitialized-zeroed.rs')
-rw-r--r-- | src/test/ui/intrinsics/panic-uninitialized-zeroed.rs | 292 |
1 files changed, 292 insertions, 0 deletions
diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs new file mode 100644 index 000000000..255151a96 --- /dev/null +++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs @@ -0,0 +1,292 @@ +// run-pass +// needs-unwind +// ignore-wasm32-bare compiled with panic=abort by default +// revisions: mir thir strict +// [thir]compile-flags: -Zthir-unsafeck +// [strict]compile-flags: -Zstrict-init-checks +// ignore-tidy-linelength + +// This test checks panic emitted from `mem::{uninitialized,zeroed}`. + +#![feature(never_type, arbitrary_enum_discriminant)] +#![allow(deprecated, invalid_value)] + +use std::{ + mem::{self, MaybeUninit, ManuallyDrop}, + panic, + ptr::NonNull, + num, +}; + +#[allow(dead_code)] +struct Foo { + x: u8, + y: !, +} + +enum Bar {} + +#[allow(dead_code)] +enum OneVariant { Variant(i32) } + +#[allow(dead_code, non_camel_case_types)] +enum OneVariant_NonZero { + Variant(i32, i32, num::NonZeroI32), + DeadVariant(Bar), +} + +// An `Aggregate` abi enum where 0 is not a valid discriminant. +#[allow(dead_code)] +#[repr(i32)] +enum NoNullVariant { + Variant1(i32, i32) = 1, + Variant2(i32, i32) = 2, +} + +// An enum with ScalarPair layout +#[allow(dead_code)] +enum LR { + Left(i64), + Right(i64), +} +#[allow(dead_code, non_camel_case_types)] +enum LR_NonZero { + Left(num::NonZeroI64), + Right(num::NonZeroI64), +} + +struct ZeroSized; + +#[allow(dead_code)] +#[repr(i32)] +enum ZeroIsValid { + Zero(u8) = 0, + One(NonNull<()>) = 1, +} + +fn test_panic_msg<T>(op: impl (FnOnce() -> T) + panic::UnwindSafe, msg: &str) { + let err = panic::catch_unwind(op).err(); + assert_eq!( + err.as_ref().and_then(|a| a.downcast_ref::<&str>()), + Some(&msg) + ); +} + +fn main() { + unsafe { + // Uninhabited types + test_panic_msg( + || mem::uninitialized::<!>(), + "attempted to instantiate uninhabited type `!`" + ); + test_panic_msg( + || mem::zeroed::<!>(), + "attempted to instantiate uninhabited type `!`" + ); + test_panic_msg( + || MaybeUninit::<!>::uninit().assume_init(), + "attempted to instantiate uninhabited type `!`" + ); + + test_panic_msg( + || mem::uninitialized::<Foo>(), + "attempted to instantiate uninhabited type `Foo`" + ); + test_panic_msg( + || mem::zeroed::<Foo>(), + "attempted to instantiate uninhabited type `Foo`" + ); + test_panic_msg( + || MaybeUninit::<Foo>::uninit().assume_init(), + "attempted to instantiate uninhabited type `Foo`" + ); + + test_panic_msg( + || mem::uninitialized::<Bar>(), + "attempted to instantiate uninhabited type `Bar`" + ); + test_panic_msg( + || mem::zeroed::<Bar>(), + "attempted to instantiate uninhabited type `Bar`" + ); + test_panic_msg( + || MaybeUninit::<Bar>::uninit().assume_init(), + "attempted to instantiate uninhabited type `Bar`" + ); + + test_panic_msg( + || mem::uninitialized::<[Foo; 2]>(), + "attempted to instantiate uninhabited type `[Foo; 2]`" + ); + test_panic_msg( + || mem::zeroed::<[Foo; 2]>(), + "attempted to instantiate uninhabited type `[Foo; 2]`" + ); + test_panic_msg( + || MaybeUninit::<[Foo; 2]>::uninit().assume_init(), + "attempted to instantiate uninhabited type `[Foo; 2]`" + ); + + test_panic_msg( + || mem::uninitialized::<[Bar; 2]>(), + "attempted to instantiate uninhabited type `[Bar; 2]`" + ); + test_panic_msg( + || mem::zeroed::<[Bar; 2]>(), + "attempted to instantiate uninhabited type `[Bar; 2]`" + ); + test_panic_msg( + || MaybeUninit::<[Bar; 2]>::uninit().assume_init(), + "attempted to instantiate uninhabited type `[Bar; 2]`" + ); + + // Types that do not like zero-initialziation + test_panic_msg( + || mem::uninitialized::<fn()>(), + "attempted to leave type `fn()` uninitialized, which is invalid" + ); + test_panic_msg( + || mem::zeroed::<fn()>(), + "attempted to zero-initialize type `fn()`, which is invalid" + ); + + test_panic_msg( + || mem::uninitialized::<*const dyn Send>(), + "attempted to leave type `*const dyn core::marker::Send` uninitialized, which is invalid" + ); + test_panic_msg( + || mem::zeroed::<*const dyn Send>(), + "attempted to zero-initialize type `*const dyn core::marker::Send`, which is invalid" + ); + + test_panic_msg( + || mem::uninitialized::<(NonNull<u32>, u32, u32)>(), + "attempted to leave type `(core::ptr::non_null::NonNull<u32>, u32, u32)` uninitialized, \ + which is invalid" + ); + + test_panic_msg( + || mem::zeroed::<(NonNull<u32>, u32, u32)>(), + "attempted to zero-initialize type `(core::ptr::non_null::NonNull<u32>, u32, u32)`, \ + which is invalid" + ); + + test_panic_msg( + || mem::uninitialized::<OneVariant_NonZero>(), + "attempted to leave type `OneVariant_NonZero` uninitialized, \ + which is invalid" + ); + test_panic_msg( + || mem::zeroed::<OneVariant_NonZero>(), + "attempted to zero-initialize type `OneVariant_NonZero`, \ + which is invalid" + ); + + test_panic_msg( + || mem::uninitialized::<LR_NonZero>(), + "attempted to leave type `LR_NonZero` uninitialized, which is invalid" + ); + + test_panic_msg( + || mem::uninitialized::<ManuallyDrop<LR_NonZero>>(), + "attempted to leave type `core::mem::manually_drop::ManuallyDrop<LR_NonZero>` uninitialized, \ + which is invalid" + ); + + test_panic_msg( + || mem::uninitialized::<NoNullVariant>(), + "attempted to leave type `NoNullVariant` uninitialized, \ + which is invalid" + ); + + test_panic_msg( + || mem::zeroed::<NoNullVariant>(), + "attempted to zero-initialize type `NoNullVariant`, \ + which is invalid" + ); + + // Types that can be zero, but not uninit. + test_panic_msg( + || mem::uninitialized::<bool>(), + "attempted to leave type `bool` uninitialized, which is invalid" + ); + + test_panic_msg( + || mem::uninitialized::<LR>(), + "attempted to leave type `LR` uninitialized, which is invalid" + ); + + test_panic_msg( + || mem::uninitialized::<ManuallyDrop<LR>>(), + "attempted to leave type `core::mem::manually_drop::ManuallyDrop<LR>` uninitialized, which is invalid" + ); + + // Some things that should work. + let _val = mem::zeroed::<bool>(); + let _val = mem::zeroed::<LR>(); + let _val = mem::zeroed::<ManuallyDrop<LR>>(); + let _val = mem::zeroed::<OneVariant>(); + let _val = mem::zeroed::<Option<&'static i32>>(); + let _val = mem::zeroed::<MaybeUninit<NonNull<u32>>>(); + let _val = mem::zeroed::<[!; 0]>(); + let _val = mem::zeroed::<ZeroIsValid>(); + let _val = mem::uninitialized::<MaybeUninit<bool>>(); + let _val = mem::uninitialized::<[!; 0]>(); + let _val = mem::uninitialized::<()>(); + let _val = mem::uninitialized::<ZeroSized>(); + + if cfg!(strict) { + test_panic_msg( + || mem::uninitialized::<i32>(), + "attempted to leave type `i32` uninitialized, which is invalid" + ); + + test_panic_msg( + || mem::uninitialized::<*const ()>(), + "attempted to leave type `*const ()` uninitialized, which is invalid" + ); + + test_panic_msg( + || mem::uninitialized::<[i32; 1]>(), + "attempted to leave type `[i32; 1]` uninitialized, which is invalid" + ); + + test_panic_msg( + || mem::zeroed::<NonNull<()>>(), + "attempted to zero-initialize type `core::ptr::non_null::NonNull<()>`, which is invalid" + ); + + test_panic_msg( + || mem::zeroed::<[NonNull<()>; 1]>(), + "attempted to zero-initialize type `[core::ptr::non_null::NonNull<()>; 1]`, which is invalid" + ); + + // FIXME(#66151) we conservatively do not error here yet (by default). + test_panic_msg( + || mem::zeroed::<LR_NonZero>(), + "attempted to zero-initialize type `LR_NonZero`, which is invalid" + ); + + test_panic_msg( + || mem::zeroed::<ManuallyDrop<LR_NonZero>>(), + "attempted to zero-initialize type `core::mem::manually_drop::ManuallyDrop<LR_NonZero>`, \ + which is invalid" + ); + } else { + // These are UB because they have not been officially blessed, but we await the resolution + // of <https://github.com/rust-lang/unsafe-code-guidelines/issues/71> before doing + // anything about that. + let _val = mem::uninitialized::<i32>(); + let _val = mem::uninitialized::<*const ()>(); + + // These are UB, but best to test them to ensure we don't become unintentionally + // stricter. + + // It's currently unchecked to create invalid enums and values inside arrays. + let _val = mem::zeroed::<LR_NonZero>(); + let _val = mem::zeroed::<[LR_NonZero; 1]>(); + let _val = mem::zeroed::<[NonNull<()>; 1]>(); + let _val = mem::uninitialized::<[NonNull<()>; 1]>(); + } + } +} |