@@ -46,13 +46,17 @@ macro_rules! try_validation {
46
46
( $e: expr, $what: expr, $where: expr, $details: expr) => { {
47
47
match $e {
48
48
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.
49
51
Err ( _) => throw_validation_failure!( $what, $where, $details) ,
50
52
}
51
53
} } ;
52
54
53
55
( $e: expr, $what: expr, $where: expr) => { {
54
56
match $e {
55
57
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.
56
60
Err ( _) => throw_validation_failure!( $what, $where) ,
57
61
}
58
62
} } ;
@@ -167,6 +171,7 @@ struct ValidityVisitor<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> {
167
171
path : Vec < PathElem > ,
168
172
ref_tracking_for_consts :
169
173
Option < & ' rt mut RefTracking < MPlaceTy < ' tcx , M :: PointerTag > , Vec < PathElem > > > ,
174
+ may_ref_to_static : bool ,
170
175
ecx : & ' rt InterpCx < ' mir , ' tcx , M > ,
171
176
}
172
177
@@ -320,9 +325,17 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M
320
325
self . check_wide_ptr_meta ( place. meta , place. layout ) ?;
321
326
}
322
327
// 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
326
339
// for the purpose of validity, consider foreign types to have
327
340
// alignment and size determined by the layout (size will be 0,
328
341
// alignment should take attributes into account).
@@ -359,10 +372,13 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M
359
372
format_args!( "a dangling {} (created from integer)" , kind) ,
360
373
self . path
361
374
) ,
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) ,
366
382
}
367
383
}
368
384
} ;
@@ -380,6 +396,12 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M
380
396
if !did. is_local ( ) || self . ecx . tcx . is_foreign_item ( did) {
381
397
return Ok ( ( ) ) ;
382
398
}
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
+ }
383
405
}
384
406
}
385
407
// 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>
638
660
err_unsup ! ( ReadPointerAsBytes ) => {
639
661
throw_validation_failure ! ( "a pointer" , self . path, "plain (non-pointer) bytes" )
640
662
}
663
+ // Propagate upwards (that will also check for unexpected errors).
641
664
_ => return Err ( err) ,
642
665
} ,
643
666
}
@@ -773,31 +796,59 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
773
796
}
774
797
775
798
impl < ' 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 (
785
800
& self ,
786
801
op : OpTy < ' tcx , M :: PointerTag > ,
787
802
path : Vec < PathElem > ,
788
803
ref_tracking_for_consts : Option <
789
804
& mut RefTracking < MPlaceTy < ' tcx , M :: PointerTag > , Vec < PathElem > > ,
790
805
> ,
806
+ may_ref_to_static : bool ,
791
807
) -> InterpResult < ' tcx > {
792
- trace ! ( "validate_operand : {:?}, {:?}" , * op, op. layout. ty) ;
808
+ trace ! ( "validate_operand_internal : {:?}, {:?}" , * op, op. layout. ty) ;
793
809
794
810
// 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 } ;
796
813
797
814
// Try to cast to ptr *once* instead of all the time.
798
815
let op = self . force_op_ptr ( op) . unwrap_or ( op) ;
799
816
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 )
802
853
}
803
854
}
0 commit comments