@@ -14,10 +14,9 @@ use std::{fmt, mem, ptr};
1414use rustc_abi:: { Align , HasDataLayout , Size } ;
1515use rustc_ast:: Mutability ;
1616use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap } ;
17- use rustc_hir:: def:: DefKind ;
1817use rustc_middle:: bug;
1918use rustc_middle:: mir:: display_allocation;
20- use rustc_middle:: ty:: { self , Instance , ParamEnv , Ty , TyCtxt } ;
19+ use rustc_middle:: ty:: { self , Instance , Ty , TyCtxt } ;
2120use tracing:: { debug, instrument, trace} ;
2221
2322use super :: {
@@ -72,6 +71,21 @@ pub enum AllocKind {
7271 Dead ,
7372}
7473
74+ /// Metadata about an `AllocId`.
75+ #[ derive( Copy , Clone , PartialEq , Debug ) ]
76+ pub struct AllocInfo {
77+ pub size : Size ,
78+ pub align : Align ,
79+ pub kind : AllocKind ,
80+ pub mutbl : Mutability ,
81+ }
82+
83+ impl AllocInfo {
84+ fn new ( size : Size , align : Align , kind : AllocKind , mutbl : Mutability ) -> Self {
85+ Self { size, align, kind, mutbl }
86+ }
87+ }
88+
7589/// The value of a function pointer.
7690#[ derive( Debug , Copy , Clone ) ]
7791pub enum FnVal < ' tcx , Other > {
@@ -524,17 +538,22 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
524538 match self . ptr_try_get_alloc_id ( ptr, 0 ) {
525539 Err ( addr) => is_offset_misaligned ( addr, align) ,
526540 Ok ( ( alloc_id, offset, _prov) ) => {
527- let ( _size, alloc_align, kind) = self . get_alloc_info ( alloc_id) ;
528- if let Some ( misalign) =
529- M :: alignment_check ( self , alloc_id, alloc_align, kind, offset, align)
530- {
541+ let alloc_info = self . get_alloc_info ( alloc_id) ;
542+ if let Some ( misalign) = M :: alignment_check (
543+ self ,
544+ alloc_id,
545+ alloc_info. align ,
546+ alloc_info. kind ,
547+ offset,
548+ align,
549+ ) {
531550 Some ( misalign)
532551 } else if M :: Provenance :: OFFSET_IS_ADDR {
533552 is_offset_misaligned ( ptr. addr ( ) . bytes ( ) , align)
534553 } else {
535554 // Check allocation alignment and offset alignment.
536- if alloc_align . bytes ( ) < align. bytes ( ) {
537- Some ( Misalignment { has : alloc_align , required : align } )
555+ if alloc_info . align . bytes ( ) < align. bytes ( ) {
556+ Some ( Misalignment { has : alloc_info . align , required : align } )
538557 } else {
539558 is_offset_misaligned ( offset. bytes ( ) , align)
540559 }
@@ -818,82 +837,45 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
818837
819838 /// Obtain the size and alignment of an allocation, even if that allocation has
820839 /// been deallocated.
821- pub fn get_alloc_info ( & self , id : AllocId ) -> ( Size , Align , AllocKind ) {
840+ pub fn get_alloc_info ( & self , id : AllocId ) -> AllocInfo {
822841 // # Regular allocations
823842 // Don't use `self.get_raw` here as that will
824843 // a) cause cycles in case `id` refers to a static
825844 // b) duplicate a global's allocation in miri
826845 if let Some ( ( _, alloc) ) = self . memory . alloc_map . get ( id) {
827- return ( alloc. size ( ) , alloc. align , AllocKind :: LiveData ) ;
846+ return AllocInfo :: new (
847+ alloc. size ( ) ,
848+ alloc. align ,
849+ AllocKind :: LiveData ,
850+ alloc. mutability ,
851+ ) ;
828852 }
829853
830854 // # Function pointers
831855 // (both global from `alloc_map` and local from `extra_fn_ptr_map`)
832856 if self . get_fn_alloc ( id) . is_some ( ) {
833- return ( Size :: ZERO , Align :: ONE , AllocKind :: Function ) ;
857+ return AllocInfo :: new ( Size :: ZERO , Align :: ONE , AllocKind :: Function , Mutability :: Not ) ;
834858 }
835859
836- // # Statics
837- // Can't do this in the match argument, we may get cycle errors since the lock would
838- // be held throughout the match.
839- match self . tcx . try_get_global_alloc ( id) {
840- Some ( GlobalAlloc :: Static ( def_id) ) => {
841- // Thread-local statics do not have a constant address. They *must* be accessed via
842- // `ThreadLocalRef`; we can never have a pointer to them as a regular constant value.
843- assert ! ( !self . tcx. is_thread_local_static( def_id) ) ;
844-
845- let DefKind :: Static { nested, .. } = self . tcx . def_kind ( def_id) else {
846- bug ! ( "GlobalAlloc::Static is not a static" )
847- } ;
848-
849- let ( size, align) = if nested {
850- // Nested anonymous statics are untyped, so let's get their
851- // size and alignment from the allocation itself. This always
852- // succeeds, as the query is fed at DefId creation time, so no
853- // evaluation actually occurs.
854- let alloc = self . tcx . eval_static_initializer ( def_id) . unwrap ( ) ;
855- ( alloc. 0 . size ( ) , alloc. 0 . align )
856- } else {
857- // Use size and align of the type for everything else. We need
858- // to do that to
859- // * avoid cycle errors in case of self-referential statics,
860- // * be able to get information on extern statics.
861- let ty = self
862- . tcx
863- . type_of ( def_id)
864- . no_bound_vars ( )
865- . expect ( "statics should not have generic parameters" ) ;
866- let layout = self . tcx . layout_of ( ParamEnv :: empty ( ) . and ( ty) ) . unwrap ( ) ;
867- assert ! ( layout. is_sized( ) ) ;
868- ( layout. size , layout. align . abi )
869- } ;
870- ( size, align, AllocKind :: LiveData )
871- }
872- Some ( GlobalAlloc :: Memory ( alloc) ) => {
873- // Need to duplicate the logic here, because the global allocations have
874- // different associated types than the interpreter-local ones.
875- let alloc = alloc. inner ( ) ;
876- ( alloc. size ( ) , alloc. align , AllocKind :: LiveData )
877- }
878- Some ( GlobalAlloc :: Function { .. } ) => {
879- bug ! ( "We already checked function pointers above" )
880- }
881- Some ( GlobalAlloc :: VTable ( ..) ) => {
882- // No data to be accessed here. But vtables are pointer-aligned.
883- return ( Size :: ZERO , self . tcx . data_layout . pointer_align . abi , AllocKind :: VTable ) ;
884- }
885- // The rest must be dead.
886- None => {
887- // Deallocated pointers are allowed, we should be able to find
888- // them in the map.
889- let ( size, align) = * self
890- . memory
891- . dead_alloc_map
892- . get ( & id)
893- . expect ( "deallocated pointers should all be recorded in `dead_alloc_map`" ) ;
894- ( size, align, AllocKind :: Dead )
895- }
860+ // # Global allocations
861+ if let Some ( global_alloc) = self . tcx . try_get_global_alloc ( id) {
862+ let ( size, align) = global_alloc. size_and_align ( * self . tcx , self . param_env ) ;
863+ let mutbl = global_alloc. mutability ( * self . tcx , self . param_env ) ;
864+ let kind = match global_alloc {
865+ GlobalAlloc :: Static { .. } | GlobalAlloc :: Memory { .. } => AllocKind :: LiveData ,
866+ GlobalAlloc :: Function { .. } => bug ! ( "We already checked function pointers above" ) ,
867+ GlobalAlloc :: VTable { .. } => AllocKind :: VTable ,
868+ } ;
869+ return AllocInfo :: new ( size, align, kind, mutbl) ;
896870 }
871+
872+ // # Dead pointers
873+ let ( size, align) = * self
874+ . memory
875+ . dead_alloc_map
876+ . get ( & id)
877+ . expect ( "deallocated pointers should all be recorded in `dead_alloc_map`" ) ;
878+ AllocInfo :: new ( size, align, AllocKind :: Dead , Mutability :: Not )
897879 }
898880
899881 /// Obtain the size and alignment of a *live* allocation.
@@ -902,11 +884,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
902884 id : AllocId ,
903885 msg : CheckInAllocMsg ,
904886 ) -> InterpResult < ' tcx , ( Size , Align ) > {
905- let ( size , align , kind ) = self . get_alloc_info ( id) ;
906- if matches ! ( kind, AllocKind :: Dead ) {
887+ let info = self . get_alloc_info ( id) ;
888+ if matches ! ( info . kind, AllocKind :: Dead ) {
907889 throw_ub ! ( PointerUseAfterFree ( id, msg) )
908890 }
909- interp_ok ( ( size, align) )
891+ interp_ok ( ( info . size , info . align ) )
910892 }
911893
912894 fn get_fn_alloc ( & self , id : AllocId ) -> Option < FnVal < ' tcx , M :: ExtraFnVal > > {
@@ -1458,7 +1440,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
14581440 let ptr = scalar. to_pointer ( self ) ?;
14591441 match self . ptr_try_get_alloc_id ( ptr, 0 ) {
14601442 Ok ( ( alloc_id, offset, _) ) => {
1461- let ( size, _align , _kind ) = self . get_alloc_info ( alloc_id) ;
1443+ let size = self . get_alloc_info ( alloc_id) . size ;
14621444 // If the pointer is out-of-bounds, it may be null.
14631445 // Note that one-past-the-end (offset == size) is still inbounds, and never null.
14641446 offset > size
0 commit comments