@@ -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