1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
|
// run-pass
// revisions: default strict
// [strict]compile-flags: -Zstrict-init-checks
// ignore-tidy-linelength
// ignore-emscripten spawning processes is not supported
// ignore-sgx no processes
// This test checks panic emitted from `mem::{uninitialized,zeroed}`.
#![feature(never_type)]
#![allow(deprecated, invalid_value)]
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::NonZeroI32),
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::NonZeroI64),
Right(num::NonZeroI64),
}
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>();
}
}
|