@@ -3494,42 +3494,76 @@ fn make_thin_self_ptr<'tcx>(
3494
3494
}
3495
3495
3496
3496
/// 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`.
3498
3498
///
3499
3499
/// This code is intentionally conservative, and will not detect
3500
3500
/// * 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)
3502
3504
///
3503
3505
/// A strict form of these checks that uses const evaluation exists in
3504
3506
/// `rustc_const_eval::might_permit_raw_init`, and a tracking issue for making these checks
3505
3507
/// stricter is <https://github.com/rust-lang/rust/issues/66151>.
3506
3508
///
3507
3509
/// FIXME: Once all the conservatism is removed from here, and the checks are ran by default,
3508
3510
/// 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
3510
3512
where
3511
3513
C : HasDataLayout + ty:: layout:: HasParamEnv < ' tcx > + ty:: layout:: HasTyCtxt < ' tcx > ,
3512
3514
{
3513
- return might_permit_raw_init_inner ( this, cx, false ) ;
3515
+ return might_permit_raw_init_inner ( this, cx, init_kind , false ) ;
3514
3516
3515
3517
fn might_permit_raw_init_inner < ' tcx , C > (
3516
3518
this : TyAndLayout < ' tcx > ,
3517
3519
cx : & C ,
3520
+ init_kind : InitKind ,
3518
3521
inside_array : bool ,
3519
3522
) -> bool
3520
3523
where
3521
3524
C : HasDataLayout + ty:: layout:: HasParamEnv < ' tcx > + ty:: layout:: HasTyCtxt < ' tcx > ,
3522
3525
{
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
3523
3548
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
+ }
3529
3561
}
3530
3562
}
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 => {
3533
3567
return true ;
3534
3568
}
3535
3569
}
@@ -3538,9 +3572,9 @@ where
3538
3572
// Check the ABI.
3539
3573
let valid = match this. abi {
3540
3574
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 ) ,
3544
3578
Abi :: Aggregate { .. } => true , // Fields are checked below.
3545
3579
} ;
3546
3580
if !valid {
@@ -3552,22 +3586,34 @@ where
3552
3586
match & this. fields {
3553
3587
FieldsShape :: Primitive | FieldsShape :: Union { .. } => { }
3554
3588
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
+ {
3556
3597
// Found non empty array with a type that is unhappy about this kind of initialization
3557
3598
return false ;
3558
3599
}
3559
3600
}
3560
3601
FieldsShape :: Arbitrary { offsets, .. } => {
3561
3602
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
+ ) {
3563
3609
// We found a field that is unhappy with this kind of initialization.
3564
3610
return false ;
3565
3611
}
3566
3612
}
3567
3613
}
3568
3614
}
3569
3615
3570
- if matches ! ( this. variants, Variants :: Multiple { .. } ) {
3616
+ if matches ! ( this. variants, Variants :: Multiple { .. } ) && init_kind == InitKind :: Uninit {
3571
3617
// All uninit enums are automatically invalid, even if their discriminant includes all values.
3572
3618
return false ;
3573
3619
}
0 commit comments