From 3315105677ce3df4a37bac8dfa45f3a45ea067f4 Mon Sep 17 00:00:00 2001 From: Kajetan Puchalski Date: Tue, 15 Oct 2024 15:32:36 +0100 Subject: [PATCH] core/ptr: Add simulate_realloc() Add a `simulate_realloc()` helper function to core/ptr to simulate reallocating memory from a pointer to some arbitrary address. The function is intended to be used with architecture features such as AArch64 Top-Byte Ignore where two different 64-bit addresses can point to the same chunk of memory due to some bits being ignored. To make the function accurately simulate an allocator, its return value needs to be annotated with `noalias` in LLVM the same way as it is done by actual allocator functions. To make that possible, add a new rustc built-in attribute `rustc_simulate_allocator` that does the annotating. --- compiler/rustc_codegen_llvm/src/attributes.rs | 4 +++ .../rustc_codegen_ssa/src/codegen_attrs.rs | 3 ++ compiler/rustc_feature/src/builtin_attrs.rs | 4 +++ .../src/middle/codegen_fn_attrs.rs | 2 ++ compiler/rustc_span/src/symbol.rs | 1 + library/core/src/ptr/mod.rs | 31 +++++++++++++++++++ 6 files changed, 45 insertions(+) diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 2c5ec9dad59f1..447b103726a3e 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -482,6 +482,10 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx); attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]); } + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::SIMULATE_ALLOCATOR) { + let no_alias = AttributeKind::NoAlias.create_attr(cx.llcx); + attributes::apply_to_llfn(llfn, AttributePlace::ReturnValue, &[no_alias]); + } if let Some(align) = codegen_fn_attrs.alignment { llvm::set_alignment(llfn, align); } diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index d536419ab3c20..c615aed6edf15 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -110,6 +110,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { sym::rustc_nounwind => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND, sym::rustc_reallocator => codegen_fn_attrs.flags |= CodegenFnAttrFlags::REALLOCATOR, sym::rustc_deallocator => codegen_fn_attrs.flags |= CodegenFnAttrFlags::DEALLOCATOR, + sym::rustc_simulate_allocator => { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::SIMULATE_ALLOCATOR + } sym::rustc_allocator_zeroed => { codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED } diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 17827b4e43b37..30b107e8b3f42 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -691,6 +691,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_allocator_zeroed, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, IMPL_DETAIL ), + rustc_attr!( + rustc_simulate_allocator, Normal, template!(Word), WarnFollowing, + EncodeCrossCrate::No, IMPL_DETAIL + ), gated!( default_lib_allocator, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, allocator_internals, experimental!(default_lib_allocator), diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 90dff0f5c7da8..4bb118f4cd7c5 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -133,6 +133,8 @@ bitflags::bitflags! { const ALLOCATOR_ZEROED = 1 << 18; /// `#[no_builtins]`: indicates that disable implicit builtin knowledge of functions for the function. const NO_BUILTINS = 1 << 19; + /// `#[rustc_simulate_allocator]`: a hint to LLVM that the function simulates an allocation + const SIMULATE_ALLOCATOR = 1 << 20; } } rustc_data_structures::external_bitflags_debug! { CodegenFnAttrFlags } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index cc3bda99a117b..7be366dcc8089 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1735,6 +1735,7 @@ symbols! { rustc_runtime, rustc_safe_intrinsic, rustc_serialize, + rustc_simulate_allocator, rustc_skip_during_method_dispatch, rustc_specialization_trait, rustc_std_internal_symbol, diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 6b07449292417..58de13d681ce1 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -446,6 +446,7 @@ // There are many unsafe functions taking pointers that don't dereference them. #![allow(clippy::not_unsafe_ptr_arg_deref)] +use crate::arch::asm; use crate::cmp::Ordering; use crate::marker::FnPtr; use crate::mem::{self, MaybeUninit}; @@ -2441,3 +2442,33 @@ pub macro addr_of($place:expr) { pub macro addr_of_mut($place:expr) { &raw mut $place } + +/// Simulate a realloc to a new address +/// +/// Intended for use with pointer tagging architecture features such as AArch64 TBI. +/// This function creates a new pointer with the address `new_address` and a brand new provenance, +/// simulating a realloc from the original address to the new address. +/// Note that this is only a simulated realloc - nothing actually gets moved or reallocated. +/// +/// SAFETY: Users *must* ensure that `new_address` actually contains the same memory as the original. +/// The primary use-case is working with various architecture pointer tagging schemes, where two +/// different 64-bit addresses can point to the same chunk of memory due to some bits being ignored. +/// When used incorrectly, this function can be used to violate the memory model in arbitrary ways. +/// Furthermore, after using this function, users must ensure that the underlying memory is only ever +/// accessed through the newly created pointer. Any accesses through the original pointer +/// (or any pointers derived from it) would be Undefined Behaviour. +#[inline(never)] +#[unstable(feature = "ptr_simulate_realloc", issue = "none")] +#[cfg_attr(not(bootstrap), rustc_simulate_allocator)] +#[allow(fuzzy_provenance_casts)] +pub unsafe fn simulate_realloc(original: *mut T, new_address: usize) -> *mut T { + // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. + let mut ptr = new_address as *mut T; + // SAFETY: This does not do anything + unsafe { + asm!("/* simulate realloc from {original} to {ptr} */", + original = in(reg) original, ptr = inout(reg) ptr); + } + // FIXME: call Miri hooks to update the address of the original allocation + ptr +}