@@ -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
35103512where
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 }
0 commit comments