@@ -113,6 +113,15 @@ pub enum PathElem {
113
113
DynDowncast ,
114
114
}
115
115
116
+ /// Extra things to check for during validation of CTFE results.
117
+ pub enum CtfeValidationMode {
118
+ /// Regular validation, nothing special happening.
119
+ Regular ,
120
+ /// Validation of a `const`. `inner` says if this is an inner, indirect allocation (as opposed
121
+ /// to the top-level const allocation).
122
+ Const { inner : bool } ,
123
+ }
124
+
116
125
/// State for tracking recursive validation of references
117
126
pub struct RefTracking < T , PATH = ( ) > {
118
127
pub seen : FxHashSet < T > ,
@@ -202,9 +211,9 @@ struct ValidityVisitor<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> {
202
211
/// starts must not be changed! `visit_fields` and `visit_array` rely on
203
212
/// this stack discipline.
204
213
path : Vec < PathElem > ,
205
- ref_tracking_for_consts :
206
- Option < & ' rt mut RefTracking < MPlaceTy < ' tcx , M :: PointerTag > , Vec < PathElem > > > ,
207
- may_ref_to_static : bool ,
214
+ ref_tracking : Option < & ' rt mut RefTracking < MPlaceTy < ' tcx , M :: PointerTag > , Vec < PathElem > > > ,
215
+ /// `None` indicates this is not validating for CTFE (but for runtime).
216
+ ctfe_mode : Option < CtfeValidationMode > ,
208
217
ecx : & ' rt InterpCx < ' mir , ' tcx , M > ,
209
218
}
210
219
@@ -418,27 +427,15 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
418
427
{ "a dangling {} (use-after-free)" , kind } ,
419
428
) ;
420
429
// Recursive checking
421
- if let Some ( ref mut ref_tracking) = self . ref_tracking_for_consts {
430
+ if let Some ( ref mut ref_tracking) = self . ref_tracking {
422
431
if let Some ( ptr) = ptr {
423
432
// not a ZST
424
433
// Skip validation entirely for some external statics
425
434
let alloc_kind = self . ecx . tcx . get_global_alloc ( ptr. alloc_id ) ;
426
435
if let Some ( GlobalAlloc :: Static ( did) ) = alloc_kind {
427
436
assert ! ( !self . ecx. tcx. is_thread_local_static( did) ) ;
428
437
assert ! ( self . ecx. tcx. is_static( did) ) ;
429
- if self . may_ref_to_static {
430
- // We skip checking other statics. These statics must be sound by
431
- // themselves, and the only way to get broken statics here is by using
432
- // unsafe code.
433
- // The reasons we don't check other statics is twofold. For one, in all
434
- // sound cases, the static was already validated on its own, and second, we
435
- // trigger cycle errors if we try to compute the value of the other static
436
- // and that static refers back to us.
437
- // We might miss const-invalid data,
438
- // but things are still sound otherwise (in particular re: consts
439
- // referring to statics).
440
- return Ok ( ( ) ) ;
441
- } else {
438
+ if matches ! ( self . ctfe_mode, Some ( CtfeValidationMode :: Const { .. } ) ) {
442
439
// See const_eval::machine::MemoryExtra::can_access_statics for why
443
440
// this check is so important.
444
441
// This check is reachable when the const just referenced the static,
@@ -447,6 +444,17 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
447
444
{ "a {} pointing to a static variable" , kind }
448
445
) ;
449
446
}
447
+ // We skip checking other statics. These statics must be sound by
448
+ // themselves, and the only way to get broken statics here is by using
449
+ // unsafe code.
450
+ // The reasons we don't check other statics is twofold. For one, in all
451
+ // sound cases, the static was already validated on its own, and second, we
452
+ // trigger cycle errors if we try to compute the value of the other static
453
+ // and that static refers back to us.
454
+ // We might miss const-invalid data,
455
+ // but things are still sound otherwise (in particular re: consts
456
+ // referring to statics).
457
+ return Ok ( ( ) ) ;
450
458
}
451
459
}
452
460
// Proceed recursively even for ZST, no reason to skip them!
@@ -504,7 +512,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
504
512
let value = self . ecx . read_scalar ( value) ?;
505
513
// NOTE: Keep this in sync with the array optimization for int/float
506
514
// types below!
507
- if self . ref_tracking_for_consts . is_some ( ) {
515
+ if self . ctfe_mode . is_some ( ) {
508
516
// Integers/floats in CTFE: Must be scalar bits, pointers are dangerous
509
517
let is_bits = value. check_init ( ) . map_or ( false , |v| v. is_bits ( ) ) ;
510
518
if !is_bits {
@@ -723,6 +731,15 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
723
731
// Sanity check: `builtin_deref` does not know any pointers that are not primitive.
724
732
assert ! ( op. layout. ty. builtin_deref( true ) . is_none( ) ) ;
725
733
734
+ // Special check preventing `UnsafeCell` in constants
735
+ if let Some ( def) = op. layout . ty . ty_adt_def ( ) {
736
+ if matches ! ( self . ctfe_mode, Some ( CtfeValidationMode :: Const { inner: true } ) )
737
+ && Some ( def. did ) == self . ecx . tcx . lang_items ( ) . unsafe_cell_type ( )
738
+ {
739
+ throw_validation_failure ! ( self . path, { "`UnsafeCell` in a `const`" } ) ;
740
+ }
741
+ }
742
+
726
743
// Recursively walk the value at its type.
727
744
self . walk_value ( op) ?;
728
745
@@ -814,7 +831,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
814
831
self . ecx ,
815
832
ptr,
816
833
size,
817
- /*allow_uninit_and_ptr*/ self . ref_tracking_for_consts . is_none ( ) ,
834
+ /*allow_uninit_and_ptr*/ self . ctfe_mode . is_none ( ) ,
818
835
) {
819
836
// In the happy case, we needn't check anything else.
820
837
Ok ( ( ) ) => { }
@@ -865,16 +882,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
865
882
& self ,
866
883
op : OpTy < ' tcx , M :: PointerTag > ,
867
884
path : Vec < PathElem > ,
868
- ref_tracking_for_consts : Option <
869
- & mut RefTracking < MPlaceTy < ' tcx , M :: PointerTag > , Vec < PathElem > > ,
870
- > ,
871
- may_ref_to_static : bool ,
885
+ ref_tracking : Option < & mut RefTracking < MPlaceTy < ' tcx , M :: PointerTag > , Vec < PathElem > > > ,
886
+ ctfe_mode : Option < CtfeValidationMode > ,
872
887
) -> InterpResult < ' tcx > {
873
888
trace ! ( "validate_operand_internal: {:?}, {:?}" , * op, op. layout. ty) ;
874
889
875
890
// Construct a visitor
876
- let mut visitor =
877
- ValidityVisitor { path, ref_tracking_for_consts, may_ref_to_static, ecx : self } ;
891
+ let mut visitor = ValidityVisitor { path, ref_tracking, ctfe_mode, ecx : self } ;
878
892
879
893
// Try to cast to ptr *once* instead of all the time.
880
894
let op = self . force_op_ptr ( op) . unwrap_or ( op) ;
@@ -902,23 +916,25 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
902
916
/// `ref_tracking` is used to record references that we encounter so that they
903
917
/// can be checked recursively by an outside driving loop.
904
918
///
905
- /// `may_ref_to_static` controls whether references are allowed to point to statics.
919
+ /// `constant` controls whether this must satisfy the rules for constants:
920
+ /// - no pointers to statics.
921
+ /// - no `UnsafeCell` or non-ZST `&mut`.
906
922
#[ inline( always) ]
907
923
pub fn const_validate_operand (
908
924
& self ,
909
925
op : OpTy < ' tcx , M :: PointerTag > ,
910
926
path : Vec < PathElem > ,
911
927
ref_tracking : & mut RefTracking < MPlaceTy < ' tcx , M :: PointerTag > , Vec < PathElem > > ,
912
- may_ref_to_static : bool ,
928
+ ctfe_mode : CtfeValidationMode ,
913
929
) -> InterpResult < ' tcx > {
914
- self . validate_operand_internal ( op, path, Some ( ref_tracking) , may_ref_to_static )
930
+ self . validate_operand_internal ( op, path, Some ( ref_tracking) , Some ( ctfe_mode ) )
915
931
}
916
932
917
933
/// This function checks the data at `op` to be runtime-valid.
918
934
/// `op` is assumed to cover valid memory if it is an indirect operand.
919
935
/// It will error if the bits at the destination do not match the ones described by the layout.
920
936
#[ inline( always) ]
921
937
pub fn validate_operand ( & self , op : OpTy < ' tcx , M :: PointerTag > ) -> InterpResult < ' tcx > {
922
- self . validate_operand_internal ( op, vec ! [ ] , None , false )
938
+ self . validate_operand_internal ( op, vec ! [ ] , None , None )
923
939
}
924
940
}
0 commit comments