@@ -524,7 +524,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
524524 match self . ptr_try_get_alloc_id ( ptr, 0 ) {
525525 Err ( addr) => is_offset_misaligned ( addr, align) ,
526526 Ok ( ( alloc_id, offset, _prov) ) => {
527- let ( _size, alloc_align, kind) = self . get_alloc_info ( alloc_id) ;
527+ let ( _size, alloc_align, kind, _mutbl ) = self . get_alloc_info ( alloc_id) ;
528528 if let Some ( misalign) =
529529 M :: alignment_check ( self , alloc_id, alloc_align, kind, offset, align)
530530 {
@@ -818,19 +818,19 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
818818
819819 /// Obtain the size and alignment of an allocation, even if that allocation has
820820 /// been deallocated.
821- pub fn get_alloc_info ( & self , id : AllocId ) -> ( Size , Align , AllocKind ) {
821+ pub fn get_alloc_info ( & self , id : AllocId ) -> ( Size , Align , AllocKind , Mutability ) {
822822 // # Regular allocations
823823 // Don't use `self.get_raw` here as that will
824824 // a) cause cycles in case `id` refers to a static
825825 // b) duplicate a global's allocation in miri
826826 if let Some ( ( _, alloc) ) = self . memory . alloc_map . get ( id) {
827- return ( alloc. size ( ) , alloc. align , AllocKind :: LiveData ) ;
827+ return ( alloc. size ( ) , alloc. align , AllocKind :: LiveData , alloc . mutability ) ;
828828 }
829829
830830 // # Function pointers
831831 // (both global from `alloc_map` and local from `extra_fn_ptr_map`)
832832 if self . get_fn_alloc ( id) . is_some ( ) {
833- return ( Size :: ZERO , Align :: ONE , AllocKind :: Function ) ;
833+ return ( Size :: ZERO , Align :: ONE , AllocKind :: Function , Mutability :: Not ) ;
834834 }
835835
836836 // # Statics
@@ -842,17 +842,17 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
842842 // `ThreadLocalRef`; we can never have a pointer to them as a regular constant value.
843843 assert ! ( !self . tcx. is_thread_local_static( def_id) ) ;
844844
845- let DefKind :: Static { nested, .. } = self . tcx . def_kind ( def_id) else {
845+ let DefKind :: Static { nested, mutability , .. } = self . tcx . def_kind ( def_id) else {
846846 bug ! ( "GlobalAlloc::Static is not a static" )
847847 } ;
848848
849- let ( size, align) = if nested {
849+ let ( size, align, mutability ) = if nested {
850850 // Nested anonymous statics are untyped, so let's get their
851851 // size and alignment from the allocation itself. This always
852852 // succeeds, as the query is fed at DefId creation time, so no
853853 // evaluation actually occurs.
854854 let alloc = self . tcx . eval_static_initializer ( def_id) . unwrap ( ) ;
855- ( alloc. 0 . size ( ) , alloc. 0 . align )
855+ ( alloc. 0 . size ( ) , alloc. 0 . align , alloc . 0 . mutability )
856856 } else {
857857 // Use size and align of the type for everything else. We need
858858 // to do that to
@@ -865,22 +865,33 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
865865 . expect ( "statics should not have generic parameters" ) ;
866866 let layout = self . tcx . layout_of ( ParamEnv :: empty ( ) . and ( ty) ) . unwrap ( ) ;
867867 assert ! ( layout. is_sized( ) ) ;
868- ( layout. size , layout. align . abi )
868+ let mutability = match mutability {
869+ Mutability :: Not if !ty. is_freeze ( * self . tcx , ParamEnv :: empty ( ) ) => {
870+ Mutability :: Not
871+ }
872+ _ => Mutability :: Mut ,
873+ } ;
874+ ( layout. size , layout. align . abi , mutability)
869875 } ;
870- ( size, align, AllocKind :: LiveData )
876+ ( size, align, AllocKind :: LiveData , mutability )
871877 }
872878 Some ( GlobalAlloc :: Memory ( alloc) ) => {
873879 // Need to duplicate the logic here, because the global allocations have
874880 // different associated types than the interpreter-local ones.
875881 let alloc = alloc. inner ( ) ;
876- ( alloc. size ( ) , alloc. align , AllocKind :: LiveData )
882+ ( alloc. size ( ) , alloc. align , AllocKind :: LiveData , alloc . mutability )
877883 }
878884 Some ( GlobalAlloc :: Function { .. } ) => {
879885 bug ! ( "We already checked function pointers above" )
880886 }
881887 Some ( GlobalAlloc :: VTable ( ..) ) => {
882888 // No data to be accessed here. But vtables are pointer-aligned.
883- return ( Size :: ZERO , self . tcx . data_layout . pointer_align . abi , AllocKind :: VTable ) ;
889+ return (
890+ Size :: ZERO ,
891+ self . tcx . data_layout . pointer_align . abi ,
892+ AllocKind :: VTable ,
893+ Mutability :: Not ,
894+ ) ;
884895 }
885896 // The rest must be dead.
886897 None => {
@@ -891,7 +902,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
891902 . dead_alloc_map
892903 . get ( & id)
893904 . expect ( "deallocated pointers should all be recorded in `dead_alloc_map`" ) ;
894- ( size, align, AllocKind :: Dead )
905+ ( size, align, AllocKind :: Dead , Mutability :: Not )
895906 }
896907 }
897908 }
@@ -902,7 +913,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
902913 id : AllocId ,
903914 msg : CheckInAllocMsg ,
904915 ) -> InterpResult < ' tcx , ( Size , Align ) > {
905- let ( size, align, kind) = self . get_alloc_info ( id) ;
916+ let ( size, align, kind, _mutbl ) = self . get_alloc_info ( id) ;
906917 if matches ! ( kind, AllocKind :: Dead ) {
907918 throw_ub ! ( PointerUseAfterFree ( id, msg) )
908919 }
@@ -1458,7 +1469,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
14581469 let ptr = scalar. to_pointer ( self ) ?;
14591470 match self . ptr_try_get_alloc_id ( ptr, 0 ) {
14601471 Ok ( ( alloc_id, offset, _) ) => {
1461- let ( size, _align, _kind) = self . get_alloc_info ( alloc_id) ;
1472+ let ( size, _align, _kind, _mutbl ) = self . get_alloc_info ( alloc_id) ;
14621473 // If the pointer is out-of-bounds, it may be null.
14631474 // Note that one-past-the-end (offset == size) is still inbounds, and never null.
14641475 offset > size
0 commit comments