Auto merge of #71274 - RalfJung:raw-init-check-aggregate, r=petrochenkov

might_permit_raw_init: also check aggregate fields

This is the next step for https://github.com/rust-lang/rust/issues/66151: when doing `mem::zeroed`/`mem::uninitialized`, also recursively check fields of aggregates (except for arrays) for whether they permit zero/uninit initialization.
This commit is contained in:
bors 2020-09-27 10:17:09 +00:00
commit b8363295d5
3 changed files with 59 additions and 8 deletions

View File

@ -1135,16 +1135,31 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
Abi::Scalar(s) => scalar_allows_raw_init(s), Abi::Scalar(s) => scalar_allows_raw_init(s),
Abi::ScalarPair(s1, s2) => scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2), Abi::ScalarPair(s1, s2) => scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2),
Abi::Vector { element: s, count } => *count == 0 || scalar_allows_raw_init(s), Abi::Vector { element: s, count } => *count == 0 || scalar_allows_raw_init(s),
Abi::Aggregate { .. } => true, // Cannot be excluded *right now*. Abi::Aggregate { .. } => true, // Fields are checked below.
}; };
if !valid { if !valid {
// This is definitely not okay. // This is definitely not okay.
trace!("might_permit_raw_init({:?}, zero={}): not valid", self.layout, zero);
return Ok(false); return Ok(false);
} }
// If we have not found an error yet, we need to recursively descend. // If we have not found an error yet, we need to recursively descend into fields.
// FIXME(#66151): For now, we are conservative and do not do this. match &self.fields {
FieldsShape::Primitive | FieldsShape::Union { .. } => {}
FieldsShape::Array { .. } => {
// FIXME(#66151): For now, we are conservative and do not check arrays.
}
FieldsShape::Arbitrary { offsets, .. } => {
for idx in 0..offsets.len() {
let field = self.field(cx, idx).to_result()?;
if !field.might_permit_raw_init(cx, zero)? {
// We found a field that is unhappy with this kind of initialization.
return Ok(false);
}
}
}
}
// FIXME(#66151): For now, we are conservative and do not check `self.variants`.
Ok(true) Ok(true)
} }
} }

View File

@ -3,7 +3,7 @@
// This test checks panic emitted from `mem::{uninitialized,zeroed}`. // This test checks panic emitted from `mem::{uninitialized,zeroed}`.
#![feature(never_type)] #![feature(never_type, arbitrary_enum_discriminant)]
#![allow(deprecated, invalid_value)] #![allow(deprecated, invalid_value)]
use std::{ use std::{
@ -24,6 +24,20 @@ enum Bar {}
#[allow(dead_code)] #[allow(dead_code)]
enum OneVariant { Variant(i32) } 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 // An enum with ScalarPair layout
#[allow(dead_code)] #[allow(dead_code)]
enum LR { enum LR {
@ -125,6 +139,7 @@ fn main() {
"attempted to zero-initialize type `std::mem::ManuallyDrop<LR_NonZero>`, \ "attempted to zero-initialize type `std::mem::ManuallyDrop<LR_NonZero>`, \
which is invalid" which is invalid"
); );
*/
test_panic_msg( test_panic_msg(
|| mem::uninitialized::<(NonNull<u32>, u32, u32)>(), || mem::uninitialized::<(NonNull<u32>, u32, u32)>(),
@ -136,7 +151,28 @@ fn main() {
"attempted to zero-initialize type `(std::ptr::NonNull<u32>, u32, u32)`, \ "attempted to zero-initialize type `(std::ptr::NonNull<u32>, u32, u32)`, \
which is invalid" 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::<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. // Types that can be zero, but not uninit.
test_panic_msg( test_panic_msg(

View File

@ -22,14 +22,14 @@ const TEST_REPOS: &[Test] = &[
Test { Test {
name: "ripgrep", name: "ripgrep",
repo: "https://github.com/BurntSushi/ripgrep", repo: "https://github.com/BurntSushi/ripgrep",
sha: "ad9befbc1d3b5c695e7f6b6734ee1b8e683edd41", sha: "3de31f752729525d85a3d1575ac1978733b3f7e7",
lock: None, lock: None,
packages: &[], packages: &[],
}, },
Test { Test {
name: "tokei", name: "tokei",
repo: "https://github.com/XAMPPRocky/tokei", repo: "https://github.com/XAMPPRocky/tokei",
sha: "a950ff128d5a435a8083b1c7577c0431f98360ca", sha: "fdf3f8cb279a7aeac0696c87e5d8b0cd946e4f9e",
lock: None, lock: None,
packages: &[], packages: &[],
}, },