@@ -46,13 +46,17 @@ macro_rules! try_validation {
4646    ( $e: expr,  $what: expr,  $where: expr,  $details: expr)  => { { 
4747        match  $e { 
4848            Ok ( x)  => x, 
49+             // We re-throw the error, so we are okay with allocation: 
50+             // this can only slow down builds that fail anyway. 
4951            Err ( _)  => throw_validation_failure!( $what,  $where,  $details) , 
5052        } 
5153    } } ; 
5254
5355    ( $e: expr,  $what: expr,  $where: expr)  => { { 
5456        match  $e { 
5557            Ok ( x)  => x, 
58+             // We re-throw the error, so we are okay with allocation: 
59+             // this can only slow down builds that fail anyway. 
5660            Err ( _)  => throw_validation_failure!( $what,  $where) , 
5761        } 
5862    } } ; 
@@ -167,6 +171,7 @@ struct ValidityVisitor<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> {
167171     path :  Vec < PathElem > , 
168172    ref_tracking_for_consts : 
169173        Option < & ' rt  mut  RefTracking < MPlaceTy < ' tcx ,  M :: PointerTag > ,  Vec < PathElem > > > , 
174+     may_ref_to_static :  bool , 
170175    ecx :  & ' rt  InterpCx < ' mir ,  ' tcx ,  M > , 
171176} 
172177
@@ -320,9 +325,17 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M
320325            self . check_wide_ptr_meta ( place. meta ,  place. layout ) ?; 
321326        } 
322327        // Make sure this is dereferenceable and all. 
323-         let  ( size,  align)  = self 
324-             . ecx 
325-             . size_and_align_of ( place. meta ,  place. layout ) ?
328+         let  size_and_align = match  self . ecx . size_and_align_of ( place. meta ,  place. layout )  { 
329+             Ok ( res)  => res, 
330+             Err ( err)  => match  err. kind  { 
331+                 err_ub ! ( InvalidMeta ( msg) )  => throw_validation_failure ! ( 
332+                     format_args!( "invalid {} metadata: {}" ,  kind,  msg) , 
333+                     self . path
334+                 ) , 
335+                 _ => bug ! ( "Unexpected error during ptr size_and_align_of: {}" ,  err) , 
336+             } , 
337+         } ; 
338+         let  ( size,  align)  = size_and_align
326339            // for the purpose of validity, consider foreign types to have 
327340            // alignment and size determined by the layout (size will be 0, 
328341            // alignment should take attributes into account). 
@@ -359,10 +372,13 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M
359372                        format_args!( "a dangling {} (created from integer)" ,  kind) , 
360373                        self . path
361374                    ) , 
362-                     _ => throw_validation_failure ! ( 
363-                         format_args!( "a dangling {} (not entirely in bounds)" ,  kind) , 
364-                         self . path
365-                     ) , 
375+                     err_unsup ! ( PointerOutOfBounds  {  .. } )  | err_unsup ! ( DanglingPointerDeref )  => { 
376+                         throw_validation_failure ! ( 
377+                             format_args!( "a dangling {} (not entirely in bounds)" ,  kind) , 
378+                             self . path
379+                         ) 
380+                     } 
381+                     _ => bug ! ( "Unexpected error during ptr inbounds test: {}" ,  err) , 
366382                } 
367383            } 
368384        } ; 
@@ -380,6 +396,12 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M
380396                    if  !did. is_local ( )  || self . ecx . tcx . is_foreign_item ( did)  { 
381397                        return  Ok ( ( ) ) ; 
382398                    } 
399+                     if  !self . may_ref_to_static  && self . ecx . tcx . is_static ( did)  { 
400+                         throw_validation_failure ! ( 
401+                             format_args!( "a {} pointing to a static variable" ,  kind) , 
402+                             self . path
403+                         ) ; 
404+                     } 
383405                } 
384406            } 
385407            // Proceed recursively even for ZST, no reason to skip them! 
@@ -638,6 +660,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
638660                err_unsup ! ( ReadPointerAsBytes )  => { 
639661                    throw_validation_failure ! ( "a pointer" ,  self . path,  "plain (non-pointer) bytes" ) 
640662                } 
663+                 // Propagate upwards (that will also check for unexpected errors). 
641664                _ => return  Err ( err) , 
642665            } , 
643666        } 
@@ -773,31 +796,59 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
773796} 
774797
775798impl < ' mir ,  ' tcx ,  M :  Machine < ' mir ,  ' tcx > >  InterpCx < ' mir ,  ' tcx ,  M >  { 
776-     /// This function checks the data at `op`. `op` is assumed to cover valid memory if it 
777-      /// is an indirect operand. 
778-      /// It will error if the bits at the destination do not match the ones described by the layout. 
779-      /// 
780-      /// `ref_tracking_for_consts` can be `None` to avoid recursive checking below references. 
781-      /// This also toggles between "run-time" (no recursion) and "compile-time" (with recursion) 
782-      /// validation (e.g., pointer values are fine in integers at runtime) and various other const 
783-      /// specific validation checks. 
784-      pub  fn  validate_operand ( 
799+     fn  validate_operand_internal ( 
785800        & self , 
786801        op :  OpTy < ' tcx ,  M :: PointerTag > , 
787802        path :  Vec < PathElem > , 
788803        ref_tracking_for_consts :  Option < 
789804            & mut  RefTracking < MPlaceTy < ' tcx ,  M :: PointerTag > ,  Vec < PathElem > > , 
790805        > , 
806+         may_ref_to_static :  bool , 
791807    )  -> InterpResult < ' tcx >  { 
792-         trace ! ( "validate_operand : {:?}, {:?}" ,  * op,  op. layout. ty) ; 
808+         trace ! ( "validate_operand_internal : {:?}, {:?}" ,  * op,  op. layout. ty) ; 
793809
794810        // Construct a visitor 
795-         let  mut  visitor = ValidityVisitor  {  path,  ref_tracking_for_consts,  ecx :  self  } ; 
811+         let  mut  visitor =
812+             ValidityVisitor  {  path,  ref_tracking_for_consts,  may_ref_to_static,  ecx :  self  } ; 
796813
797814        // Try to cast to ptr *once* instead of all the time. 
798815        let  op = self . force_op_ptr ( op) . unwrap_or ( op) ; 
799816
800-         // Run it 
801-         visitor. visit_value ( op) 
817+         // Run it. 
818+         match  visitor. visit_value ( op)  { 
819+             Ok ( ( ) )  => Ok ( ( ) ) , 
820+             Err ( err)  if  matches ! ( err. kind,  err_unsup!( ValidationFailure  {  .. } ) )  => Err ( err) , 
821+             Err ( err)  if  cfg ! ( debug_assertions)  => { 
822+                 bug ! ( "Unexpected error during validation: {}" ,  err) 
823+             } 
824+             Err ( err)  => Err ( err) , 
825+         } 
826+     } 
827+ 
828+     /// This function checks the data at `op` to be const-valid. 
829+      /// `op` is assumed to cover valid memory if it is an indirect operand. 
830+      /// It will error if the bits at the destination do not match the ones described by the layout. 
831+      /// 
832+      /// `ref_tracking` is used to record references that we encounter so that they 
833+      /// can be checked recursively by an outside driving loop. 
834+      /// 
835+      /// `may_ref_to_static` controls whether references are allowed to point to statics. 
836+      #[ inline( always) ]  
837+     pub  fn  const_validate_operand ( 
838+         & self , 
839+         op :  OpTy < ' tcx ,  M :: PointerTag > , 
840+         path :  Vec < PathElem > , 
841+         ref_tracking :  & mut  RefTracking < MPlaceTy < ' tcx ,  M :: PointerTag > ,  Vec < PathElem > > , 
842+         may_ref_to_static :  bool , 
843+     )  -> InterpResult < ' tcx >  { 
844+         self . validate_operand_internal ( op,  path,  Some ( ref_tracking) ,  may_ref_to_static) 
845+     } 
846+ 
847+     /// This function checks the data at `op` to be runtime-valid. 
848+      /// `op` is assumed to cover valid memory if it is an indirect operand. 
849+      /// It will error if the bits at the destination do not match the ones described by the layout. 
850+      #[ inline( always) ]  
851+     pub  fn  validate_operand ( & self ,  op :  OpTy < ' tcx ,  M :: PointerTag > )  -> InterpResult < ' tcx >  { 
852+         self . validate_operand_internal ( op,  vec ! [ ] ,  None ,  false ) 
802853    } 
803854} 
0 commit comments