Skip to content

Commit 6770c21

Browse files
committed
Still do the type walking for zero init checks
1 parent c84936e commit 6770c21

File tree

3 files changed

+80
-39
lines changed

3 files changed

+80
-39
lines changed

compiler/rustc_const_eval/src/might_permit_raw_init.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ pub fn might_permit_raw_init<'tcx>(
1515
) -> bool {
1616
let strict = tcx.sess.opts.unstable_opts.strict_init_checks;
1717

18-
if strict || kind == InitKind::Zero {
18+
if strict {
1919
let machine = CompileTimeInterpreter::new(Limit::new(0), false);
2020

2121
let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine);
@@ -38,6 +38,6 @@ pub fn might_permit_raw_init<'tcx>(
3838
cx.validate_operand(&ot).is_ok()
3939
} else {
4040
let layout_cx = LayoutCx { tcx, param_env: ParamEnv::reveal_all() };
41-
layout::might_permit_raw_init(ty, &layout_cx)
41+
layout::might_permit_raw_init(ty, &layout_cx, kind)
4242
}
4343
}

compiler/rustc_middle/src/ty/layout.rs

Lines changed: 63 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3494,42 +3494,76 @@ fn make_thin_self_ptr<'tcx>(
34943494
}
34953495

34963496
/// Determines if this type permits "raw" initialization by just transmuting some
3497-
/// uninitialized memory into an instance of `T`.
3497+
/// memory into an instance of `T`.
34983498
///
34993499
/// This code is intentionally conservative, and will not detect
35003500
/// * making uninitialized types who have a full valid range (ints, floats, raw pointers)
3501-
/// * uninit invalid `&[T]` where T has align 1 (only inside arrays)
3501+
/// * uninit `&[T]` where T has align 1 (only inside arrays). This includes `&str`
3502+
/// * zero init enums where a discriminant with tag 0 exists, but is invalid to be zeroed
3503+
/// * zero init type that does not allow zero init (only inside arrays)
35023504
///
35033505
/// A strict form of these checks that uses const evaluation exists in
35043506
/// `rustc_const_eval::might_permit_raw_init`, and a tracking issue for making these checks
35053507
/// stricter is <https://github.com/rust-lang/rust/issues/66151>.
35063508
///
35073509
/// FIXME: Once all the conservatism is removed from here, and the checks are ran by default,
35083510
/// we can use the const evaluation checks always instead.
3509-
pub fn might_permit_raw_init<'tcx, C>(this: TyAndLayout<'tcx>, cx: &C) -> bool
3511+
pub fn might_permit_raw_init<'tcx, C>(this: TyAndLayout<'tcx>, cx: &C, init_kind: InitKind) -> bool
35103512
where
35113513
C: HasDataLayout + ty::layout::HasParamEnv<'tcx> + ty::layout::HasTyCtxt<'tcx>,
35123514
{
3513-
return might_permit_raw_init_inner(this, cx, false);
3515+
return might_permit_raw_init_inner(this, cx, init_kind, false);
35143516

35153517
fn might_permit_raw_init_inner<'tcx, C>(
35163518
this: TyAndLayout<'tcx>,
35173519
cx: &C,
3520+
init_kind: InitKind,
35183521
inside_array: bool,
35193522
) -> bool
35203523
where
35213524
C: HasDataLayout + ty::layout::HasParamEnv<'tcx> + ty::layout::HasTyCtxt<'tcx>,
35223525
{
3526+
let scalar_allows_raw_init = move |s: Scalar| -> bool {
3527+
match init_kind {
3528+
InitKind::Zero => {
3529+
// The range must contain 0.
3530+
s.valid_range(cx).contains(0)
3531+
}
3532+
InitKind::Uninit => {
3533+
// FIXME(#66151) This should be "is the type a union", but that's pending on a
3534+
// resolution to https://github.com/rust-lang/unsafe-code-guidelines/issues/71
3535+
// And likely a large number of crates fail with those rules, though no crater
3536+
// run has been done yet.
3537+
//
3538+
// The range must include all values.
3539+
s.is_always_valid(cx)
3540+
}
3541+
}
3542+
};
3543+
3544+
// These are bypasses in order to try not to break quite as many crates so quickly.
3545+
// They are being done only if we're inside an array, to ensure we don't panic on *less*
3546+
// things than we did before this change.
3547+
// See: https://github.com/rust-lang/rust/pull/99389
35233548
if inside_array {
3524-
if let ty::Ref(_, inner, _) = this.ty.kind() {
3525-
if let ty::Slice(inner) = inner.kind() {
3526-
let penv = ty::ParamEnv::reveal_all().and(*inner);
3527-
if let Ok(l) = cx.tcx().layout_of(penv) {
3528-
return l.layout.align().abi == Align::ONE;
3549+
match init_kind {
3550+
// FIXME(#66151) We need to ignore uninit slice references with an alignment of 1
3551+
// (as in, &[u8] and &str)
3552+
// Since if we do not, old versions of `hyper` with no semver compatible fix
3553+
// (0.11, 0.12, 0.13) break.
3554+
InitKind::Uninit => {
3555+
if let ty::Ref(_, inner, _) = this.ty.kind() {
3556+
let penv = ty::ParamEnv::reveal_all().and(*inner);
3557+
if let Ok(l) = cx.tcx().layout_of(penv) {
3558+
return l.layout.align().abi == Align::ONE
3559+
&& l.layout.size() == Size::ZERO;
3560+
}
35293561
}
35303562
}
3531-
3532-
if let ty::Str = inner.kind() {
3563+
// FIXME(#66151) We need to ignore all forms of zero data being made inside an
3564+
// array, because old versions of crossbeam make zeroed data, sometimes at an
3565+
// arbitrary type chosen by the user (such as for crossbeam-channel).
3566+
InitKind::Zero => {
35333567
return true;
35343568
}
35353569
}
@@ -3538,9 +3572,9 @@ where
35383572
// Check the ABI.
35393573
let valid = match this.abi {
35403574
Abi::Uninhabited => false, // definitely UB
3541-
Abi::Scalar(s) => s.is_always_valid(cx),
3542-
Abi::ScalarPair(s1, s2) => s1.is_always_valid(cx) && s2.is_always_valid(cx),
3543-
Abi::Vector { element: s, count } => count == 0 || s.is_always_valid(cx),
3575+
Abi::Scalar(s) => scalar_allows_raw_init(s),
3576+
Abi::ScalarPair(s1, s2) => scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2),
3577+
Abi::Vector { element: s, count } => count == 0 || scalar_allows_raw_init(s),
35443578
Abi::Aggregate { .. } => true, // Fields are checked below.
35453579
};
35463580
if !valid {
@@ -3552,22 +3586,34 @@ where
35523586
match &this.fields {
35533587
FieldsShape::Primitive | FieldsShape::Union { .. } => {}
35543588
FieldsShape::Array { count, .. } => {
3555-
if *count > 0 && !might_permit_raw_init_inner(this.field(cx, 0), cx, true) {
3589+
if *count > 0
3590+
&& !might_permit_raw_init_inner(
3591+
this.field(cx, 0),
3592+
cx,
3593+
init_kind,
3594+
/*inside_array*/ true,
3595+
)
3596+
{
35563597
// Found non empty array with a type that is unhappy about this kind of initialization
35573598
return false;
35583599
}
35593600
}
35603601
FieldsShape::Arbitrary { offsets, .. } => {
35613602
for idx in 0..offsets.len() {
3562-
if !might_permit_raw_init_inner(this.field(cx, idx), cx, inside_array) {
3603+
if !might_permit_raw_init_inner(
3604+
this.field(cx, idx),
3605+
cx,
3606+
init_kind,
3607+
inside_array,
3608+
) {
35633609
// We found a field that is unhappy with this kind of initialization.
35643610
return false;
35653611
}
35663612
}
35673613
}
35683614
}
35693615

3570-
if matches!(this.variants, Variants::Multiple { .. }) {
3616+
if matches!(this.variants, Variants::Multiple { .. }) && init_kind == InitKind::Uninit {
35713617
// All uninit enums are automatically invalid, even if their discriminant includes all values.
35723618
return false;
35733619
}

src/test/ui/intrinsics/panic-uninitialized-zeroed.rs

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -274,42 +274,27 @@ fn main() {
274274
"attempted to leave type `SoManyVariants` uninitialized, which is invalid"
275275
);
276276

277-
test_panic_msg(
278-
|| mem::zeroed::<[(&'static [u8], &'static str); 1]>(),
279-
"attempted to zero-initialize type `[(&[u8], &str); 1]`, which is invalid"
280-
);
281-
282277
test_panic_msg(
283278
|| mem::uninitialized::<[&'static [u16]; 1]>(),
284279
"attempted to leave type `[&[u16]; 1]` uninitialized, which is invalid"
285280
);
286281

287-
test_panic_msg(
288-
|| mem::zeroed::<[NonNull<()>; 1]>(),
289-
"attempted to zero-initialize type `[core::ptr::non_null::NonNull<()>; 1]`, which is invalid"
290-
);
291-
292282
test_panic_msg(
293283
|| mem::uninitialized::<[NonNull<()>; 1]>(),
294284
"attempted to leave type `[core::ptr::non_null::NonNull<()>; 1]` uninitialized, which is invalid"
295285
);
296286

297-
test_panic_msg(
287+
test_strict_panic_msg(
298288
|| mem::zeroed::<LR_NonZero>(),
299289
"attempted to zero-initialize type `LR_NonZero`, which is invalid"
300290
);
301291

302-
test_panic_msg(
303-
|| mem::zeroed::<[LR_NonZero; 1]>(),
304-
"attempted to zero-initialize type `[LR_NonZero; 1]`, which is invalid"
305-
);
306-
307-
test_panic_msg(
292+
test_strict_panic_msg(
308293
|| mem::zeroed::<[LR_NonZero; 1]>(),
309294
"attempted to zero-initialize type `[LR_NonZero; 1]`, which is invalid"
310295
);
311296

312-
test_panic_msg(
297+
test_strict_panic_msg(
313298
|| mem::zeroed::<ManuallyDrop<LR_NonZero>>(),
314299
"attempted to zero-initialize type `core::mem::manually_drop::ManuallyDrop<LR_NonZero>`, \
315300
which is invalid"
@@ -355,8 +340,18 @@ fn main() {
355340
);
356341

357342
test_strict_panic_msg(
358-
|| mem::uninitialized::<[(&'static [u8], &'static str); 1]>(),
359-
"attempted to leave type `[(&[u8], &str); 1]` uninitialized, which is invalid"
343+
|| mem::uninitialized::<[(&'static [u8], &'static str, &()); 1]>(),
344+
"attempted to leave type `[(&[u8], &str, &()); 1]` uninitialized, which is invalid"
345+
);
346+
347+
test_strict_panic_msg(
348+
|| mem::zeroed::<[(&'static [u8], &'static str); 1]>(),
349+
"attempted to zero-initialize type `[(&[u8], &str); 1]`, which is invalid"
350+
);
351+
352+
test_strict_panic_msg(
353+
|| mem::zeroed::<[NonNull<()>; 1]>(),
354+
"attempted to zero-initialize type `[core::ptr::non_null::NonNull<()>; 1]`, which is invalid"
360355
);
361356
}
362357
}

0 commit comments

Comments
 (0)