mirror of https://github.com/rust-lang/rust
397 lines
13 KiB
Rust
397 lines
13 KiB
Rust
//@ run-pass
|
|
//@ revisions: default strict
|
|
//@ [strict]compile-flags: -Zstrict-init-checks
|
|
// ignore-tidy-linelength
|
|
//@ ignore-wasm32 spawning processes is not supported
|
|
//@ ignore-sgx no processes
|
|
//
|
|
// This test checks panic emitted from `mem::{uninitialized,zeroed}`.
|
|
#![allow(deprecated, invalid_value)]
|
|
#![feature(never_type)]
|
|
|
|
use std::{
|
|
mem::{self, MaybeUninit, ManuallyDrop},
|
|
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::NonZero<i32>),
|
|
DeadVariant(Bar),
|
|
}
|
|
|
|
#[allow(dead_code, non_camel_case_types)]
|
|
enum OneVariant_Ref {
|
|
Variant(&'static i32),
|
|
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::NonZero<i64>),
|
|
Right(num::NonZero<i64>),
|
|
}
|
|
|
|
struct ZeroSized;
|
|
|
|
#[allow(dead_code)]
|
|
#[repr(i32)]
|
|
enum ZeroIsValid {
|
|
Zero(u8) = 0,
|
|
One(NonNull<()>) = 1,
|
|
}
|
|
|
|
#[track_caller]
|
|
fn test_panic_msg<T, F: (FnOnce() -> T) + 'static>(op: F, msg: &str) {
|
|
use std::{panic, env, process};
|
|
|
|
// The tricky part is that we can't just run `op`, as that would *abort* the process.
|
|
// So instead, we reinvoke this process with the caller location as argument.
|
|
// For the purpose of this test, the line number is unique enough.
|
|
// If we are running in such a re-invocation, we skip all the tests *except* for the one with that type name.
|
|
let our_loc = panic::Location::caller().line().to_string();
|
|
let mut args = env::args();
|
|
let this = args.next().unwrap();
|
|
if let Some(loc) = args.next() {
|
|
if loc == our_loc {
|
|
op();
|
|
panic!("we did not abort");
|
|
} else {
|
|
// Nothing, we are running another test.
|
|
}
|
|
} else {
|
|
// Invoke new process for actual test, and check result.
|
|
let mut cmd = process::Command::new(this);
|
|
cmd.arg(our_loc);
|
|
let res = cmd.output().unwrap();
|
|
assert!(!res.status.success(), "test did not fail");
|
|
let stderr = String::from_utf8_lossy(&res.stderr);
|
|
assert!(stderr.contains(msg), "test did not contain expected output: looking for {:?}, output:\n{}", msg, stderr);
|
|
}
|
|
}
|
|
|
|
#[track_caller]
|
|
fn test_panic_msg_only_if_strict<T>(op: impl (FnOnce() -> T) + 'static, msg: &str) {
|
|
if !cfg!(strict) {
|
|
// Just run it.
|
|
op();
|
|
} else {
|
|
test_panic_msg(op, 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 don't allow either.
|
|
test_panic_msg(
|
|
|| mem::zeroed::<&i32>(),
|
|
"attempted to zero-initialize type `&i32`, which is invalid"
|
|
);
|
|
test_panic_msg(
|
|
|| mem::uninitialized::<&i32>(),
|
|
"attempted to leave type `&i32` uninitialized, which is invalid"
|
|
);
|
|
|
|
test_panic_msg(
|
|
|| mem::zeroed::<Box<[i32; 0]>>(),
|
|
"attempted to zero-initialize type `alloc::boxed::Box<[i32; 0]>`, which is invalid"
|
|
);
|
|
test_panic_msg(
|
|
|| mem::uninitialized::<Box<[i32; 0]>>(),
|
|
"attempted to leave type `alloc::boxed::Box<[i32; 0]>` uninitialized, which is invalid"
|
|
);
|
|
|
|
test_panic_msg(
|
|
|| mem::zeroed::<Box<u8>>(),
|
|
"attempted to zero-initialize type `alloc::boxed::Box<u8>`, which is invalid"
|
|
);
|
|
test_panic_msg(
|
|
|| mem::uninitialized::<Box<u8>>(),
|
|
"attempted to leave type `alloc::boxed::Box<u8>` uninitialized, which is invalid"
|
|
);
|
|
|
|
test_panic_msg(
|
|
|| mem::zeroed::<&[i32]>(),
|
|
"attempted to zero-initialize type `&[i32]`, which is invalid"
|
|
);
|
|
test_panic_msg(
|
|
|| mem::uninitialized::<&[i32]>(),
|
|
"attempted to leave type `&[i32]` uninitialized, which is invalid"
|
|
);
|
|
|
|
test_panic_msg(
|
|
|| mem::zeroed::<&(u8, [u8])>(),
|
|
"attempted to zero-initialize type `&(u8, [u8])`, which is invalid"
|
|
);
|
|
test_panic_msg(
|
|
|| mem::uninitialized::<&(u8, [u8])>(),
|
|
"attempted to leave type `&(u8, [u8])` uninitialized, which is invalid"
|
|
);
|
|
|
|
test_panic_msg(
|
|
|| mem::zeroed::<&dyn Send>(),
|
|
"attempted to zero-initialize type `&dyn core::marker::Send`, which is invalid"
|
|
);
|
|
test_panic_msg(
|
|
|| mem::uninitialized::<&dyn Send>(),
|
|
"attempted to leave type `&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::<*const dyn Send>(),
|
|
"attempted to leave type `*const dyn core::marker::Send` 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"
|
|
);
|
|
|
|
test_panic_msg(
|
|
|| mem::zeroed::<OneVariant_Ref>(),
|
|
"attempted to zero-initialize type `OneVariant_Ref`, \
|
|
which is invalid"
|
|
);
|
|
test_panic_msg(
|
|
|| mem::uninitialized::<OneVariant_Ref>(),
|
|
"attempted to leave type `OneVariant_Ref` uninitialized, which is invalid"
|
|
);
|
|
|
|
// Types where both are invalid, but we allow uninit since the 0x01-filling is not LLVM UB.
|
|
test_panic_msg(
|
|
|| mem::zeroed::<fn()>(),
|
|
"attempted to zero-initialize type `fn()`, which is invalid"
|
|
);
|
|
test_panic_msg_only_if_strict(
|
|
|| mem::uninitialized::<fn()>(),
|
|
"attempted to leave type `fn()` uninitialized, which is invalid"
|
|
);
|
|
|
|
test_panic_msg(
|
|
|| mem::zeroed::<&()>(),
|
|
"attempted to zero-initialize type `&()`, which is invalid"
|
|
);
|
|
test_panic_msg_only_if_strict(
|
|
|| mem::uninitialized::<&()>(),
|
|
"attempted to leave type `&()` uninitialized, which is invalid"
|
|
);
|
|
|
|
test_panic_msg(
|
|
|| mem::zeroed::<&[u8]>(),
|
|
"attempted to zero-initialize type `&[u8]`, which is invalid"
|
|
);
|
|
test_panic_msg_only_if_strict(
|
|
|| mem::uninitialized::<&[u8]>(),
|
|
"attempted to leave type `&[u8]` uninitialized, which is invalid"
|
|
);
|
|
|
|
test_panic_msg(
|
|
|| mem::zeroed::<&str>(),
|
|
"attempted to zero-initialize type `&str`, which is invalid"
|
|
);
|
|
test_panic_msg_only_if_strict(
|
|
|| mem::uninitialized::<&str>(),
|
|
"attempted to leave type `&str` 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_only_if_strict(
|
|
|| 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::<OneVariant_NonZero>(),
|
|
"attempted to zero-initialize type `OneVariant_NonZero`, \
|
|
which is invalid"
|
|
);
|
|
test_panic_msg_only_if_strict(
|
|
|| mem::uninitialized::<OneVariant_NonZero>(),
|
|
"attempted to leave type `OneVariant_NonZero` uninitialized, which is invalid"
|
|
);
|
|
|
|
// Types where both are invalid but we allow the zeroed form since it is not LLVM UB.
|
|
test_panic_msg_only_if_strict(
|
|
|| mem::zeroed::<LR_NonZero>(),
|
|
"attempted to zero-initialize type `LR_NonZero`, which is invalid"
|
|
);
|
|
test_panic_msg(
|
|
|| mem::uninitialized::<LR_NonZero>(),
|
|
"attempted to leave type `LR_NonZero` uninitialized, which is invalid"
|
|
);
|
|
|
|
test_panic_msg_only_if_strict(
|
|
|| mem::zeroed::<ManuallyDrop<LR_NonZero>>(),
|
|
"attempted to zero-initialize type `core::mem::manually_drop::ManuallyDrop<LR_NonZero>`, \
|
|
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"
|
|
);
|
|
|
|
// Some strict-only things
|
|
test_panic_msg_only_if_strict(
|
|
|| mem::uninitialized::<i32>(),
|
|
"attempted to leave type `i32` uninitialized, which is invalid"
|
|
);
|
|
|
|
test_panic_msg_only_if_strict(
|
|
|| mem::uninitialized::<*const ()>(),
|
|
"attempted to leave type `*const ()` uninitialized, which is invalid"
|
|
);
|
|
|
|
test_panic_msg_only_if_strict(
|
|
|| mem::uninitialized::<[i32; 1]>(),
|
|
"attempted to leave type `[i32; 1]` uninitialized, which is invalid"
|
|
);
|
|
|
|
test_panic_msg_only_if_strict(
|
|
|| mem::zeroed::<[NonNull<()>; 1]>(),
|
|
"attempted to zero-initialize type `[core::ptr::non_null::NonNull<()>; 1]`, which is invalid"
|
|
);
|
|
|
|
// Types that can be zero, but not uninit (though some are mitigated).
|
|
let _val = mem::zeroed::<LR>();
|
|
test_panic_msg(
|
|
|| mem::uninitialized::<LR>(),
|
|
"attempted to leave type `LR` uninitialized, which is invalid"
|
|
);
|
|
|
|
let _val = mem::zeroed::<ManuallyDrop<LR>>();
|
|
test_panic_msg(
|
|
|| mem::uninitialized::<ManuallyDrop<LR>>(),
|
|
"attempted to leave type `core::mem::manually_drop::ManuallyDrop<LR>` uninitialized, which is invalid"
|
|
);
|
|
|
|
let _val = mem::zeroed::<bool>();
|
|
test_panic_msg_only_if_strict(
|
|
|| mem::uninitialized::<bool>(),
|
|
"attempted to leave type `bool` uninitialized, which is invalid"
|
|
);
|
|
|
|
let _val = mem::zeroed::<OneVariant>();
|
|
test_panic_msg_only_if_strict(
|
|
|| mem::uninitialized::<OneVariant>(),
|
|
"attempted to leave type `OneVariant` uninitialized, which is invalid"
|
|
);
|
|
|
|
// Some things that are actually allowed.
|
|
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>();
|
|
}
|
|
}
|