diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 81b9d73b952..4055e3f0d50 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -472,7 +472,7 @@ fn report_validation_error<'tcx>( backtrace.print_backtrace(); let bytes = ecx.print_alloc_bytes_for_diagnostics(alloc_id); - let (size, align, _) = ecx.get_alloc_info(alloc_id); + let (size, align, ..) = ecx.get_alloc_info(alloc_id); let raw_bytes = errors::RawBytesNote { size: size.bytes(), align: align.bytes(), bytes }; crate::const_eval::report( diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 1ad8ffa4b53..cc7ce1df923 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -524,7 +524,7 @@ fn is_offset_misaligned(offset: u64, align: Align) -> Option { match self.ptr_try_get_alloc_id(ptr, 0) { Err(addr) => is_offset_misaligned(addr, align), Ok((alloc_id, offset, _prov)) => { - let (_size, alloc_align, kind) = self.get_alloc_info(alloc_id); + let (_size, alloc_align, kind, _mutbl) = self.get_alloc_info(alloc_id); if let Some(misalign) = M::alignment_check(self, alloc_id, alloc_align, kind, offset, align) { @@ -818,19 +818,19 @@ pub fn is_alloc_live(&self, id: AllocId) -> bool { /// Obtain the size and alignment of an allocation, even if that allocation has /// been deallocated. - pub fn get_alloc_info(&self, id: AllocId) -> (Size, Align, AllocKind) { + pub fn get_alloc_info(&self, id: AllocId) -> (Size, Align, AllocKind, Mutability) { // # Regular allocations // Don't use `self.get_raw` here as that will // a) cause cycles in case `id` refers to a static // b) duplicate a global's allocation in miri if let Some((_, alloc)) = self.memory.alloc_map.get(id) { - return (alloc.size(), alloc.align, AllocKind::LiveData); + return (alloc.size(), alloc.align, AllocKind::LiveData, alloc.mutability); } // # Function pointers // (both global from `alloc_map` and local from `extra_fn_ptr_map`) if self.get_fn_alloc(id).is_some() { - return (Size::ZERO, Align::ONE, AllocKind::Function); + return (Size::ZERO, Align::ONE, AllocKind::Function, Mutability::Not); } // # Statics @@ -842,17 +842,17 @@ pub fn get_alloc_info(&self, id: AllocId) -> (Size, Align, AllocKind) { // `ThreadLocalRef`; we can never have a pointer to them as a regular constant value. assert!(!self.tcx.is_thread_local_static(def_id)); - let DefKind::Static { nested, .. } = self.tcx.def_kind(def_id) else { + let DefKind::Static { nested, mutability, .. } = self.tcx.def_kind(def_id) else { bug!("GlobalAlloc::Static is not a static") }; - let (size, align) = if nested { + let (size, align, mutability) = if nested { // Nested anonymous statics are untyped, so let's get their // size and alignment from the allocation itself. This always // succeeds, as the query is fed at DefId creation time, so no // evaluation actually occurs. let alloc = self.tcx.eval_static_initializer(def_id).unwrap(); - (alloc.0.size(), alloc.0.align) + (alloc.0.size(), alloc.0.align, alloc.0.mutability) } else { // Use size and align of the type for everything else. We need // to do that to @@ -865,22 +865,33 @@ pub fn get_alloc_info(&self, id: AllocId) -> (Size, Align, AllocKind) { .expect("statics should not have generic parameters"); let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap(); assert!(layout.is_sized()); - (layout.size, layout.align.abi) + let mutability = match mutability { + Mutability::Not if !ty.is_freeze(*self.tcx, ParamEnv::empty()) => { + Mutability::Not + } + _ => Mutability::Mut, + }; + (layout.size, layout.align.abi, mutability) }; - (size, align, AllocKind::LiveData) + (size, align, AllocKind::LiveData, mutability) } Some(GlobalAlloc::Memory(alloc)) => { // Need to duplicate the logic here, because the global allocations have // different associated types than the interpreter-local ones. let alloc = alloc.inner(); - (alloc.size(), alloc.align, AllocKind::LiveData) + (alloc.size(), alloc.align, AllocKind::LiveData, alloc.mutability) } Some(GlobalAlloc::Function { .. }) => { bug!("We already checked function pointers above") } Some(GlobalAlloc::VTable(..)) => { // No data to be accessed here. But vtables are pointer-aligned. - return (Size::ZERO, self.tcx.data_layout.pointer_align.abi, AllocKind::VTable); + return ( + Size::ZERO, + self.tcx.data_layout.pointer_align.abi, + AllocKind::VTable, + Mutability::Not, + ); } // The rest must be dead. None => { @@ -891,7 +902,7 @@ pub fn get_alloc_info(&self, id: AllocId) -> (Size, Align, AllocKind) { .dead_alloc_map .get(&id) .expect("deallocated pointers should all be recorded in `dead_alloc_map`"); - (size, align, AllocKind::Dead) + (size, align, AllocKind::Dead, Mutability::Not) } } } @@ -902,7 +913,7 @@ fn get_live_alloc_size_and_align( id: AllocId, msg: CheckInAllocMsg, ) -> InterpResult<'tcx, (Size, Align)> { - let (size, align, kind) = self.get_alloc_info(id); + let (size, align, kind, _mutbl) = self.get_alloc_info(id); if matches!(kind, AllocKind::Dead) { throw_ub!(PointerUseAfterFree(id, msg)) } @@ -1458,7 +1469,7 @@ pub fn scalar_may_be_null(&self, scalar: Scalar) -> InterpResult< let ptr = scalar.to_pointer(self)?; match self.ptr_try_get_alloc_id(ptr, 0) { Ok((alloc_id, offset, _)) => { - let (size, _align, _kind) = self.get_alloc_info(alloc_id); + let (size, _align, _kind, _mutbl) = self.get_alloc_info(alloc_id); // If the pointer is out-of-bounds, it may be null. // Note that one-past-the-end (offset == size) is still inbounds, and never null. offset > size diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index cd2c1ef3613..d7532c6e01a 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -594,7 +594,7 @@ fn check_safe_pointer( } // Dangling and Mutability check. - let (size, _align, alloc_kind) = self.ecx.get_alloc_info(alloc_id); + let (size, _align, alloc_kind, _mutbl) = self.ecx.get_alloc_info(alloc_id); if alloc_kind == AllocKind::Dead { // This can happen for zero-sized references. We can't have *any* references to // non-existing allocations in const-eval though, interning rejects them all as diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index 7b377a1c4cd..8b59ca63a43 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -157,7 +157,7 @@ fn addr_from_alloc_id_uncached( ) -> InterpResult<'tcx, u64> { let ecx = self.eval_context_ref(); let mut rng = ecx.machine.rng.borrow_mut(); - let (size, align, kind) = ecx.get_alloc_info(alloc_id); + let (size, align, kind, _mutbl) = ecx.get_alloc_info(alloc_id); // This is either called immediately after allocation (and then cached), or when // adjusting `tcx` pointers (which never get freed). So assert that we are looking // at a live allocation. This also ensures that we never re-assign an address to an diff --git a/src/tools/miri/src/borrow_tracker/mod.rs b/src/tools/miri/src/borrow_tracker/mod.rs index 72319decb94..3ee00a1dcf4 100644 --- a/src/tools/miri/src/borrow_tracker/mod.rs +++ b/src/tools/miri/src/borrow_tracker/mod.rs @@ -363,7 +363,7 @@ fn on_stack_pop( // If it does exist, then we have the guarantee that the // pointer is readable, and the implicit read access inserted // will never cause UB on the pointer itself. - let (_, _, kind) = this.get_alloc_info(*alloc_id); + let (_, _, kind, _mutbl) = this.get_alloc_info(*alloc_id); if matches!(kind, AllocKind::LiveData) { let alloc_extra = this.get_alloc_extra(*alloc_id)?; // can still fail for `extern static` let alloc_borrow_tracker = &alloc_extra.borrow_tracker.as_ref().unwrap(); diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index 47fe41d9ecd..b42b70b4d2f 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -626,7 +626,7 @@ fn sb_reborrow( return interp_ok(()) }; - let (_size, _align, alloc_kind) = this.get_alloc_info(alloc_id); + let (_size, _align, alloc_kind, _mutbl) = this.get_alloc_info(alloc_id); match alloc_kind { AllocKind::LiveData => { // This should have alloc_extra data, but `get_alloc_extra` can still fail @@ -1017,7 +1017,7 @@ fn sb_expose_tag(&mut self, alloc_id: AllocId, tag: BorTag) -> InterpResult<'tcx // Function pointers and dead objects don't have an alloc_extra so we ignore them. // This is okay because accessing them is UB anyway, no need for any Stacked Borrows checks. // NOT using `get_alloc_extra_mut` since this might be a read-only allocation! - let (_size, _align, kind) = this.get_alloc_info(alloc_id); + let (_size, _align, kind, _mutbl) = this.get_alloc_info(alloc_id); match kind { AllocKind::LiveData => { // This should have alloc_extra data, but `get_alloc_extra` can still fail diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index 40467aa4bc1..799950e4c94 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -538,7 +538,7 @@ fn tb_expose_tag(&mut self, alloc_id: AllocId, tag: BorTag) -> InterpResult<'tcx // Function pointers and dead objects don't have an alloc_extra so we ignore them. // This is okay because accessing them is UB anyway, no need for any Tree Borrows checks. // NOT using `get_alloc_extra_mut` since this might be a read-only allocation! - let (_size, _align, kind) = this.get_alloc_info(alloc_id); + let (_size, _align, kind, _mutbl) = this.get_alloc_info(alloc_id); match kind { AllocKind::LiveData => { // This should have alloc_extra data, but `get_alloc_extra` can still fail diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 72e8952c543..c8c9070f290 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -1125,7 +1125,7 @@ fn extern_static_pointer( let Provenance::Concrete { alloc_id, .. } = ptr.provenance else { panic!("extern_statics cannot contain wildcards") }; - let (shim_size, shim_align, _kind) = ecx.get_alloc_info(alloc_id); + let (shim_size, shim_align, _kind, _mutbl) = ecx.get_alloc_info(alloc_id); let def_ty = ecx.tcx.type_of(def_id).instantiate_identity(); let extern_decl_layout = ecx.tcx.layout_of(ty::ParamEnv::empty().and(def_ty)).unwrap(); if extern_decl_layout.size != shim_size || extern_decl_layout.align.abi != shim_align { diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 18578c7acc9..a6733af9faa 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -409,7 +409,7 @@ fn emulate_foreign_item_inner( ); } if let Ok((alloc_id, offset, ..)) = this.ptr_try_get_alloc_id(ptr, 0) { - let (_size, alloc_align, _kind) = this.get_alloc_info(alloc_id); + let (_size, alloc_align, _kind, _mutbl) = this.get_alloc_info(alloc_id); // If the newly promised alignment is bigger than the native alignment of this // allocation, and bigger than the previously promised alignment, then set it. if align > alloc_align