@@ -524,7 +524,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
524
524
match self . ptr_try_get_alloc_id ( ptr, 0 ) {
525
525
Err ( addr) => is_offset_misaligned ( addr, align) ,
526
526
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) ;
528
528
if let Some ( misalign) =
529
529
M :: alignment_check ( self , alloc_id, alloc_align, kind, offset, align)
530
530
{
@@ -818,19 +818,19 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
818
818
819
819
/// Obtain the size and alignment of an allocation, even if that allocation has
820
820
/// 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 ) {
822
822
// # Regular allocations
823
823
// Don't use `self.get_raw` here as that will
824
824
// a) cause cycles in case `id` refers to a static
825
825
// b) duplicate a global's allocation in miri
826
826
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 ) ;
828
828
}
829
829
830
830
// # Function pointers
831
831
// (both global from `alloc_map` and local from `extra_fn_ptr_map`)
832
832
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 ) ;
834
834
}
835
835
836
836
// # Statics
@@ -842,17 +842,17 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
842
842
// `ThreadLocalRef`; we can never have a pointer to them as a regular constant value.
843
843
assert ! ( !self . tcx. is_thread_local_static( def_id) ) ;
844
844
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 {
846
846
bug ! ( "GlobalAlloc::Static is not a static" )
847
847
} ;
848
848
849
- let ( size, align) = if nested {
849
+ let ( size, align, mutability ) = if nested {
850
850
// Nested anonymous statics are untyped, so let's get their
851
851
// size and alignment from the allocation itself. This always
852
852
// succeeds, as the query is fed at DefId creation time, so no
853
853
// evaluation actually occurs.
854
854
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 )
856
856
} else {
857
857
// Use size and align of the type for everything else. We need
858
858
// to do that to
@@ -865,22 +865,33 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
865
865
. expect ( "statics should not have generic parameters" ) ;
866
866
let layout = self . tcx . layout_of ( ParamEnv :: empty ( ) . and ( ty) ) . unwrap ( ) ;
867
867
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)
869
875
} ;
870
- ( size, align, AllocKind :: LiveData )
876
+ ( size, align, AllocKind :: LiveData , mutability )
871
877
}
872
878
Some ( GlobalAlloc :: Memory ( alloc) ) => {
873
879
// Need to duplicate the logic here, because the global allocations have
874
880
// different associated types than the interpreter-local ones.
875
881
let alloc = alloc. inner ( ) ;
876
- ( alloc. size ( ) , alloc. align , AllocKind :: LiveData )
882
+ ( alloc. size ( ) , alloc. align , AllocKind :: LiveData , alloc . mutability )
877
883
}
878
884
Some ( GlobalAlloc :: Function { .. } ) => {
879
885
bug ! ( "We already checked function pointers above" )
880
886
}
881
887
Some ( GlobalAlloc :: VTable ( ..) ) => {
882
888
// 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
+ ) ;
884
895
}
885
896
// The rest must be dead.
886
897
None => {
@@ -891,7 +902,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
891
902
. dead_alloc_map
892
903
. get ( & id)
893
904
. expect ( "deallocated pointers should all be recorded in `dead_alloc_map`" ) ;
894
- ( size, align, AllocKind :: Dead )
905
+ ( size, align, AllocKind :: Dead , Mutability :: Not )
895
906
}
896
907
}
897
908
}
@@ -902,7 +913,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
902
913
id : AllocId ,
903
914
msg : CheckInAllocMsg ,
904
915
) -> 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) ;
906
917
if matches ! ( kind, AllocKind :: Dead ) {
907
918
throw_ub ! ( PointerUseAfterFree ( id, msg) )
908
919
}
@@ -1458,7 +1469,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
1458
1469
let ptr = scalar. to_pointer ( self ) ?;
1459
1470
match self . ptr_try_get_alloc_id ( ptr, 0 ) {
1460
1471
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) ;
1462
1473
// If the pointer is out-of-bounds, it may be null.
1463
1474
// Note that one-past-the-end (offset == size) is still inbounds, and never null.
1464
1475
offset > size
0 commit comments