Add flag for stricter checks on uninit/zeroed
This commit is contained in:
parent
43d9f3859e
commit
dd9f31d000
6 changed files with 116 additions and 26 deletions
|
@ -894,6 +894,15 @@ impl Scalar {
|
|||
Scalar::Union { .. } => true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if this type can be left uninit.
|
||||
#[inline]
|
||||
pub fn is_uninit_valid(&self) -> bool {
|
||||
match *self {
|
||||
Scalar::Initialized { .. } => false,
|
||||
Scalar::Union { .. } => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes how the fields of a type are located in memory.
|
||||
|
@ -1355,6 +1364,14 @@ pub struct PointeeInfo {
|
|||
pub address_space: AddressSpace,
|
||||
}
|
||||
|
||||
/// Used in `might_permit_raw_init` to indicate the kind of initialisation
|
||||
/// that is checked to be valid
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum InitKind {
|
||||
Zero,
|
||||
Uninit,
|
||||
}
|
||||
|
||||
/// Trait that needs to be implemented by the higher-level type representation
|
||||
/// (e.g. `rustc_middle::ty::Ty`), to provide `rustc_target::abi` functionality.
|
||||
pub trait TyAbiInterface<'a, C>: Sized {
|
||||
|
@ -1461,26 +1478,37 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
|
|||
|
||||
/// Determines if this type permits "raw" initialization by just transmuting some
|
||||
/// memory into an instance of `T`.
|
||||
/// `zero` indicates if the memory is zero-initialized, or alternatively
|
||||
/// left entirely uninitialized.
|
||||
///
|
||||
/// `init_kind` indicates if the memory is zero-initialized or left uninitialized.
|
||||
///
|
||||
/// `strict` is an opt-in debugging flag added in #97323 that enables more checks.
|
||||
///
|
||||
/// This is conservative: in doubt, it will answer `true`.
|
||||
///
|
||||
/// FIXME: Once we removed all the conservatism, we could alternatively
|
||||
/// create an all-0/all-undef constant and run the const value validator to see if
|
||||
/// this is a valid value for the given type.
|
||||
pub fn might_permit_raw_init<C>(self, cx: &C, zero: bool) -> bool
|
||||
pub fn might_permit_raw_init<C>(self, cx: &C, init_kind: InitKind, strict: bool) -> bool
|
||||
where
|
||||
Self: Copy,
|
||||
Ty: TyAbiInterface<'a, C>,
|
||||
C: HasDataLayout,
|
||||
{
|
||||
let scalar_allows_raw_init = move |s: Scalar| -> bool {
|
||||
if zero {
|
||||
// The range must contain 0.
|
||||
s.valid_range(cx).contains(0)
|
||||
} else {
|
||||
// The range must include all values.
|
||||
s.is_always_valid(cx)
|
||||
match init_kind {
|
||||
InitKind::Zero => {
|
||||
// The range must contain 0.
|
||||
s.valid_range(cx).contains(0)
|
||||
}
|
||||
InitKind::Uninit => {
|
||||
if strict {
|
||||
// The type must be allowed to be uninit (which means "is a union").
|
||||
s.is_uninit_valid()
|
||||
} else {
|
||||
// The range must include all values.
|
||||
s.is_always_valid(cx)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1500,12 +1528,19 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
|
|||
// If we have not found an error yet, we need to recursively descend into fields.
|
||||
match &self.fields {
|
||||
FieldsShape::Primitive | FieldsShape::Union { .. } => {}
|
||||
FieldsShape::Array { .. } => {
|
||||
// FIXME(#66151): For now, we are conservative and do not check arrays.
|
||||
FieldsShape::Array { count, .. } => {
|
||||
// FIXME(#66151): For now, we are conservative and do not check arrays by default.
|
||||
if strict
|
||||
&& *count > 0
|
||||
&& !self.field(cx, 0).might_permit_raw_init(cx, init_kind, strict)
|
||||
{
|
||||
// Found non empty array with a type that is unhappy about this kind of initialization
|
||||
return false;
|
||||
}
|
||||
}
|
||||
FieldsShape::Arbitrary { offsets, .. } => {
|
||||
for idx in 0..offsets.len() {
|
||||
if !self.field(cx, idx).might_permit_raw_init(cx, zero) {
|
||||
if !self.field(cx, idx).might_permit_raw_init(cx, init_kind, strict) {
|
||||
// We found a field that is unhappy with this kind of initialization.
|
||||
return false;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue