add const_make_global; err for const_allocate ptrs if didn't call
Co-Authored-By: Ralf Jung <post@ralfj.de> Co-Authored-By: Oli Scherer <github333195615777966@oli-obk.de>
This commit is contained in:
parent
9c3064e131
commit
3f2dc2bd1a
31 changed files with 361 additions and 30 deletions
|
|
@ -56,6 +56,17 @@ const_eval_const_context = {$kind ->
|
|||
*[other] {""}
|
||||
}
|
||||
|
||||
const_eval_const_heap_ptr_in_final = encountered `const_allocate` pointer in final value that was not made global
|
||||
.note = use `const_make_global` to make allocated pointers immutable before returning
|
||||
|
||||
const_eval_const_make_global_ptr_already_made_global = attempting to call `const_make_global` twice on the same allocation {$alloc}
|
||||
|
||||
const_eval_const_make_global_ptr_is_non_heap = pointer passed to `const_make_global` does not point to a heap allocation: {$ptr}
|
||||
|
||||
const_eval_const_make_global_with_dangling_ptr = pointer passed to `const_make_global` is dangling: {$ptr}
|
||||
|
||||
const_eval_const_make_global_with_offset = making {$ptr} global which does not point to the beginning of an object
|
||||
|
||||
const_eval_copy_nonoverlapping_overlapping =
|
||||
`copy_nonoverlapping` called on overlapping ranges
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::mem;
|
|||
|
||||
use rustc_errors::{Diag, DiagArgName, DiagArgValue, DiagMessage, IntoDiagArg};
|
||||
use rustc_middle::mir::AssertKind;
|
||||
use rustc_middle::mir::interpret::{Provenance, ReportedErrorInfo};
|
||||
use rustc_middle::mir::interpret::{AllocId, Provenance, ReportedErrorInfo};
|
||||
use rustc_middle::query::TyCtxtAt;
|
||||
use rustc_middle::ty::layout::LayoutError;
|
||||
use rustc_middle::ty::{ConstInt, TyCtxt};
|
||||
|
|
@ -22,8 +22,22 @@ pub enum ConstEvalErrKind {
|
|||
ModifiedGlobal,
|
||||
RecursiveStatic,
|
||||
AssertFailure(AssertKind<ConstInt>),
|
||||
Panic { msg: Symbol, line: u32, col: u32, file: Symbol },
|
||||
Panic {
|
||||
msg: Symbol,
|
||||
line: u32,
|
||||
col: u32,
|
||||
file: Symbol,
|
||||
},
|
||||
WriteThroughImmutablePointer,
|
||||
/// Called `const_make_global` twice.
|
||||
ConstMakeGlobalPtrAlreadyMadeGlobal(AllocId),
|
||||
/// Called `const_make_global` on a non-heap pointer.
|
||||
ConstMakeGlobalPtrIsNonHeap(String),
|
||||
/// Called `const_make_global` on a dangling pointer.
|
||||
ConstMakeGlobalWithDanglingPtr(String),
|
||||
/// Called `const_make_global` on a pointer that does not start at the
|
||||
/// beginning of an object.
|
||||
ConstMakeGlobalWithOffset(String),
|
||||
}
|
||||
|
||||
impl MachineStopType for ConstEvalErrKind {
|
||||
|
|
@ -38,6 +52,12 @@ impl MachineStopType for ConstEvalErrKind {
|
|||
RecursiveStatic => const_eval_recursive_static,
|
||||
AssertFailure(x) => x.diagnostic_message(),
|
||||
WriteThroughImmutablePointer => const_eval_write_through_immutable_pointer,
|
||||
ConstMakeGlobalPtrAlreadyMadeGlobal { .. } => {
|
||||
const_eval_const_make_global_ptr_already_made_global
|
||||
}
|
||||
ConstMakeGlobalPtrIsNonHeap(_) => const_eval_const_make_global_ptr_is_non_heap,
|
||||
ConstMakeGlobalWithDanglingPtr(_) => const_eval_const_make_global_with_dangling_ptr,
|
||||
ConstMakeGlobalWithOffset(_) => const_eval_const_make_global_with_offset,
|
||||
}
|
||||
}
|
||||
fn add_args(self: Box<Self>, adder: &mut dyn FnMut(DiagArgName, DiagArgValue)) {
|
||||
|
|
@ -51,6 +71,14 @@ impl MachineStopType for ConstEvalErrKind {
|
|||
Panic { msg, .. } => {
|
||||
adder("msg".into(), msg.into_diag_arg(&mut None));
|
||||
}
|
||||
ConstMakeGlobalPtrIsNonHeap(ptr)
|
||||
| ConstMakeGlobalWithOffset(ptr)
|
||||
| ConstMakeGlobalWithDanglingPtr(ptr) => {
|
||||
adder("ptr".into(), ptr.into_diag_arg(&mut None));
|
||||
}
|
||||
ConstMakeGlobalPtrAlreadyMadeGlobal(alloc) => {
|
||||
adder("alloc".into(), alloc.into_diag_arg(&mut None));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
|
|||
// Since evaluation had no errors, validate the resulting constant.
|
||||
const_validate_mplace(ecx, &ret, cid)?;
|
||||
|
||||
// Only report this after validation, as validaiton produces much better diagnostics.
|
||||
// Only report this after validation, as validation produces much better diagnostics.
|
||||
// FIXME: ensure validation always reports this and stop making interning care about it.
|
||||
|
||||
match intern_result {
|
||||
|
|
|
|||
|
|
@ -169,13 +169,15 @@ pub type CompileTimeInterpCx<'tcx> = InterpCx<'tcx, CompileTimeMachine<'tcx>>;
|
|||
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||
pub enum MemoryKind {
|
||||
Heap,
|
||||
Heap { was_made_global: bool },
|
||||
}
|
||||
|
||||
impl fmt::Display for MemoryKind {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
MemoryKind::Heap => write!(f, "heap allocation"),
|
||||
MemoryKind::Heap { was_made_global } => {
|
||||
write!(f, "heap allocation{}", if *was_made_global { " (made global)" } else { "" })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -184,7 +186,7 @@ impl interpret::MayLeak for MemoryKind {
|
|||
#[inline(always)]
|
||||
fn may_leak(self) -> bool {
|
||||
match self {
|
||||
MemoryKind::Heap => false,
|
||||
MemoryKind::Heap { was_made_global } => was_made_global,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -420,7 +422,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
|
|||
let ptr = ecx.allocate_ptr(
|
||||
Size::from_bytes(size),
|
||||
align,
|
||||
interpret::MemoryKind::Machine(MemoryKind::Heap),
|
||||
interpret::MemoryKind::Machine(MemoryKind::Heap { was_made_global: false }),
|
||||
AllocInit::Uninit,
|
||||
)?;
|
||||
ecx.write_pointer(ptr, dest)?;
|
||||
|
|
@ -453,10 +455,17 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
|
|||
ecx.deallocate_ptr(
|
||||
ptr,
|
||||
Some((size, align)),
|
||||
interpret::MemoryKind::Machine(MemoryKind::Heap),
|
||||
interpret::MemoryKind::Machine(MemoryKind::Heap { was_made_global: false }),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
sym::const_make_global => {
|
||||
let ptr = ecx.read_pointer(&args[0])?;
|
||||
ecx.make_const_heap_ptr_global(ptr)?;
|
||||
ecx.write_pointer(ptr, dest)?;
|
||||
}
|
||||
|
||||
// The intrinsic represents whether the value is known to the optimizer (LLVM).
|
||||
// We're not doing any optimizations here, so there is no optimizer that could know the value.
|
||||
// (We know the value here in the machine of course, but this is the runtime of that code,
|
||||
|
|
|
|||
|
|
@ -43,6 +43,14 @@ pub(crate) struct MutablePtrInFinal {
|
|||
pub kind: InternKind,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(const_eval_const_heap_ptr_in_final)]
|
||||
#[note]
|
||||
pub(crate) struct ConstHeapPtrInFinal {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(const_eval_unstable_in_stable_exposed)]
|
||||
pub(crate) struct UnstableInStableExposed {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ use super::{
|
|||
};
|
||||
use crate::const_eval;
|
||||
use crate::const_eval::DummyMachine;
|
||||
use crate::errors::NestedStaticInThreadLocal;
|
||||
use crate::errors::{ConstHeapPtrInFinal, NestedStaticInThreadLocal};
|
||||
|
||||
pub trait CompileTimeMachine<'tcx, T> = Machine<
|
||||
'tcx,
|
||||
|
|
@ -55,6 +55,35 @@ impl HasStaticRootDefId for const_eval::CompileTimeMachine<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
pub enum DisallowInternReason {
|
||||
ConstHeap,
|
||||
}
|
||||
|
||||
/// A trait for controlling whether memory allocated in the interpreter can be interned.
|
||||
///
|
||||
/// This prevents us from interning `const_allocate` pointers that have not been made
|
||||
/// global through `const_make_global`.
|
||||
pub trait CanIntern {
|
||||
fn disallows_intern(&self) -> Option<DisallowInternReason>;
|
||||
}
|
||||
|
||||
impl CanIntern for const_eval::MemoryKind {
|
||||
fn disallows_intern(&self) -> Option<DisallowInternReason> {
|
||||
match self {
|
||||
const_eval::MemoryKind::Heap { was_made_global: false } => {
|
||||
Some(DisallowInternReason::ConstHeap)
|
||||
}
|
||||
const_eval::MemoryKind::Heap { was_made_global: true } => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CanIntern for ! {
|
||||
fn disallows_intern(&self) -> Option<DisallowInternReason> {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
/// Intern an allocation. Returns `Err` if the allocation does not exist in the local memory.
|
||||
///
|
||||
/// `mutability` can be used to force immutable interning: if it is `Mutability::Not`, the
|
||||
|
|
@ -62,7 +91,7 @@ impl HasStaticRootDefId for const_eval::CompileTimeMachine<'_> {
|
|||
/// already mutable (as a sanity check).
|
||||
///
|
||||
/// Returns an iterator over all relocations referred to by this allocation.
|
||||
fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>(
|
||||
fn intern_shallow<'tcx, T: CanIntern, M: CompileTimeMachine<'tcx, T>>(
|
||||
ecx: &mut InterpCx<'tcx, M>,
|
||||
alloc_id: AllocId,
|
||||
mutability: Mutability,
|
||||
|
|
@ -71,9 +100,26 @@ fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>(
|
|||
trace!("intern_shallow {:?}", alloc_id);
|
||||
// remove allocation
|
||||
// FIXME(#120456) - is `swap_remove` correct?
|
||||
let Some((_kind, mut alloc)) = ecx.memory.alloc_map.swap_remove(&alloc_id) else {
|
||||
let Some((kind, mut alloc)) = ecx.memory.alloc_map.swap_remove(&alloc_id) else {
|
||||
return Err(());
|
||||
};
|
||||
|
||||
match kind {
|
||||
MemoryKind::Machine(x) if let Some(reason) = x.disallows_intern() => match reason {
|
||||
// attempting to intern a `const_allocate`d pointer that was not made global via
|
||||
// `const_make_global`. We emit an error here but don't return an `Err`. The `Err`
|
||||
// is for pointers that we can't intern at all (i.e. dangling pointers). We still
|
||||
// (recursively) intern this pointer because we don't have to worry about the
|
||||
// additional paperwork involved with _not_ interning it, such as storing it in
|
||||
// the dead memory map and having to deal with additional "dangling pointer"
|
||||
// messages if someone tries to store the non-made-global ptr in the final value.
|
||||
DisallowInternReason::ConstHeap => {
|
||||
ecx.tcx.dcx().emit_err(ConstHeapPtrInFinal { span: ecx.tcx.span });
|
||||
}
|
||||
},
|
||||
MemoryKind::Machine(_) | MemoryKind::Stack | MemoryKind::CallerLocation => {}
|
||||
}
|
||||
|
||||
// Set allocation mutability as appropriate. This is used by LLVM to put things into
|
||||
// read-only memory, and also by Miri when evaluating other globals that
|
||||
// access this one.
|
||||
|
|
@ -99,7 +145,7 @@ fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>(
|
|||
} else {
|
||||
ecx.tcx.set_alloc_id_memory(alloc_id, alloc);
|
||||
}
|
||||
Ok(alloc.0.0.provenance().ptrs().iter().map(|&(_, prov)| prov))
|
||||
Ok(alloc.inner().provenance().ptrs().iter().map(|&(_, prov)| prov))
|
||||
}
|
||||
|
||||
/// Creates a new `DefId` and feeds all the right queries to make this `DefId`
|
||||
|
|
@ -181,7 +227,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval
|
|||
}
|
||||
InternKind::Static(Mutability::Not) => {
|
||||
(
|
||||
// Outermost allocation is mutable if `!Freeze`.
|
||||
// Outermost allocation is mutable if `!Freeze` i.e. contains interior mutable types.
|
||||
if ret.layout.ty.is_freeze(*ecx.tcx, ecx.typing_env) {
|
||||
Mutability::Not
|
||||
} else {
|
||||
|
|
@ -321,7 +367,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval
|
|||
|
||||
/// Intern `ret`. This function assumes that `ret` references no other allocation.
|
||||
#[instrument(level = "debug", skip(ecx))]
|
||||
pub fn intern_const_alloc_for_constprop<'tcx, T, M: CompileTimeMachine<'tcx, T>>(
|
||||
pub fn intern_const_alloc_for_constprop<'tcx, T: CanIntern, M: CompileTimeMachine<'tcx, T>>(
|
||||
ecx: &mut InterpCx<'tcx, M>,
|
||||
alloc_id: AllocId,
|
||||
) -> InterpResult<'tcx, ()> {
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ use super::{
|
|||
Misalignment, Pointer, PointerArithmetic, Provenance, Scalar, alloc_range, err_ub,
|
||||
err_ub_custom, interp_ok, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format,
|
||||
};
|
||||
use crate::const_eval::ConstEvalErrKind;
|
||||
use crate::fluent_generated as fluent;
|
||||
|
||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||
|
|
@ -311,6 +312,49 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
interp_ok(new_ptr)
|
||||
}
|
||||
|
||||
/// mark the `const_allocate`d pointer immutable so we can intern it.
|
||||
pub fn make_const_heap_ptr_global(
|
||||
&mut self,
|
||||
ptr: Pointer<Option<M::Provenance>>,
|
||||
) -> InterpResult<'tcx>
|
||||
where
|
||||
M: Machine<'tcx, MemoryKind = crate::const_eval::MemoryKind>,
|
||||
{
|
||||
let (alloc_id, offset, _) = self.ptr_get_alloc_id(ptr, 0)?;
|
||||
if offset.bytes() != 0 {
|
||||
return Err(ConstEvalErrKind::ConstMakeGlobalWithOffset(format!("{ptr:?}"))).into();
|
||||
}
|
||||
|
||||
let not_local_heap =
|
||||
matches!(self.tcx.try_get_global_alloc(alloc_id), Some(GlobalAlloc::Memory(_)));
|
||||
|
||||
if not_local_heap {
|
||||
return Err(ConstEvalErrKind::ConstMakeGlobalPtrIsNonHeap(format!("{ptr:?}"))).into();
|
||||
}
|
||||
|
||||
let (kind, alloc) = self.memory.alloc_map.get_mut_or(alloc_id, || {
|
||||
Err(ConstEvalErrKind::ConstMakeGlobalWithDanglingPtr(format!("{ptr:?}")))
|
||||
})?;
|
||||
|
||||
alloc.mutability = Mutability::Not;
|
||||
|
||||
match kind {
|
||||
MemoryKind::Stack | MemoryKind::CallerLocation => {
|
||||
return Err(ConstEvalErrKind::ConstMakeGlobalPtrIsNonHeap(format!("{ptr:?}")))
|
||||
.into();
|
||||
}
|
||||
MemoryKind::Machine(crate::const_eval::MemoryKind::Heap { was_made_global }) => {
|
||||
if *was_made_global {
|
||||
return Err(ConstEvalErrKind::ConstMakeGlobalPtrAlreadyMadeGlobal(alloc_id))
|
||||
.into();
|
||||
}
|
||||
*was_made_global = true;
|
||||
}
|
||||
}
|
||||
|
||||
interp_ok(())
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn deallocate_ptr(
|
||||
&mut self,
|
||||
|
|
|
|||
|
|
@ -52,9 +52,8 @@ fn check_validity_requirement_strict<'tcx>(
|
|||
|
||||
let mut cx = InterpCx::new(cx.tcx(), DUMMY_SP, cx.typing_env, machine);
|
||||
|
||||
let allocated = cx
|
||||
.allocate(ty, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap))
|
||||
.expect("OOM: failed to allocate for uninit check");
|
||||
let allocated =
|
||||
cx.allocate(ty, MemoryKind::Stack).expect("OOM: failed to allocate for uninit check");
|
||||
|
||||
if kind == ValidityRequirement::Zero {
|
||||
cx.write_bytes_ptr(
|
||||
|
|
@ -185,7 +184,10 @@ pub(crate) fn validate_scalar_in_layout<'tcx>(
|
|||
bug!("could not compute layout of {scalar:?}:{ty:?}")
|
||||
};
|
||||
let allocated = cx
|
||||
.allocate(layout, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap))
|
||||
.allocate(
|
||||
layout,
|
||||
MemoryKind::Machine(crate::const_eval::MemoryKind::Heap { was_made_global: false }),
|
||||
)
|
||||
.expect("OOM: failed to allocate for uninit check");
|
||||
|
||||
cx.write_scalar(scalar, &allocated).unwrap();
|
||||
|
|
|
|||
|
|
@ -422,6 +422,9 @@ pub(crate) fn check_intrinsic_type(
|
|||
vec![Ty::new_mut_ptr(tcx, tcx.types.u8), tcx.types.usize, tcx.types.usize],
|
||||
tcx.types.unit,
|
||||
),
|
||||
sym::const_make_global => {
|
||||
(0, 0, vec![Ty::new_mut_ptr(tcx, tcx.types.u8)], Ty::new_imm_ptr(tcx, tcx.types.u8))
|
||||
}
|
||||
|
||||
sym::ptr_offset_from => (
|
||||
1,
|
||||
|
|
|
|||
|
|
@ -257,7 +257,7 @@ pub enum InvalidProgramInfo<'tcx> {
|
|||
/// Details of why a pointer had to be in-bounds.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum CheckInAllocMsg {
|
||||
/// We are access memory.
|
||||
/// We are accessing memory.
|
||||
MemoryAccess,
|
||||
/// We are doing pointer arithmetic.
|
||||
InboundsPointerArithmetic,
|
||||
|
|
|
|||
|
|
@ -715,6 +715,7 @@ symbols! {
|
|||
const_indexing,
|
||||
const_let,
|
||||
const_loop,
|
||||
const_make_global,
|
||||
const_mut_refs,
|
||||
const_panic,
|
||||
const_panic_fmt,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
use core::error::Error;
|
||||
use core::fmt::{self, Debug, Display, Formatter};
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
use core::intrinsics::const_allocate;
|
||||
use core::intrinsics::{const_allocate, const_make_global};
|
||||
use core::marker::PhantomData;
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
use core::marker::Unsize;
|
||||
|
|
@ -340,9 +340,10 @@ impl<H> WithHeader<H> {
|
|||
alloc.add(metadata_offset).cast();
|
||||
// SAFETY: `*metadata_ptr` is within the allocation.
|
||||
metadata_ptr.write(ptr::metadata::<Dyn>(ptr::dangling::<T>() as *const Dyn));
|
||||
|
||||
// SAFETY: valid heap allocation
|
||||
const_make_global(alloc);
|
||||
// SAFETY: we have just written the metadata.
|
||||
&*(metadata_ptr)
|
||||
&*metadata_ptr
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -2533,6 +2533,15 @@ pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize)
|
|||
// Runtime NOP
|
||||
}
|
||||
|
||||
#[rustc_const_unstable(feature = "const_heap", issue = "79597")]
|
||||
#[rustc_nounwind]
|
||||
#[rustc_intrinsic]
|
||||
#[miri::intrinsic_fallback_is_spec]
|
||||
pub const unsafe fn const_make_global(ptr: *mut u8) -> *const u8 {
|
||||
// const eval overrides this function; at runtime, it is a NOP.
|
||||
ptr
|
||||
}
|
||||
|
||||
/// Returns whether we should perform contract-checking at runtime.
|
||||
///
|
||||
/// This is meant to be similar to the ub_checks intrinsic, in terms
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@ const FOO_RAW: *const i32 = foo();
|
|||
|
||||
const fn foo() -> &'static i32 {
|
||||
let t = unsafe {
|
||||
let i = intrinsics::const_allocate(4, 4) as * mut i32;
|
||||
let i = intrinsics::const_allocate(4, 4) as *mut i32;
|
||||
*i = 20;
|
||||
i
|
||||
};
|
||||
unsafe { &*t }
|
||||
unsafe { &*(intrinsics::const_make_global(t as *mut u8) as *mut i32) }
|
||||
}
|
||||
fn main() {
|
||||
assert_eq!(*FOO, 20);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
error[E0080]: constructing invalid value at .<deref>: encountered uninitialized memory, but expected an integer
|
||||
--> $DIR/alloc_intrinsic_uninit.rs:7:1
|
||||
|
|
||||
LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) };
|
||||
LL | const BAR: &i32 = unsafe {
|
||||
| ^^^^^^^^^^^^^^^ it is undefined behavior to use this value
|
||||
|
|
||||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
error[E0080]: constructing invalid value at .<deref>: encountered uninitialized memory, but expected an integer
|
||||
--> $DIR/alloc_intrinsic_uninit.rs:7:1
|
||||
|
|
||||
LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) };
|
||||
LL | const BAR: &i32 = unsafe {
|
||||
| ^^^^^^^^^^^^^^^ it is undefined behavior to use this value
|
||||
|
|
||||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#![feature(const_heap)]
|
||||
use std::intrinsics;
|
||||
|
||||
const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) };
|
||||
//~^ ERROR: uninitialized memory
|
||||
const BAR: &i32 = unsafe { //~ ERROR: uninitialized memory
|
||||
&*(intrinsics::const_make_global(intrinsics::const_allocate(4, 4)) as *mut i32)
|
||||
};
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -7,5 +7,6 @@ use std::intrinsics;
|
|||
|
||||
const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 };
|
||||
//~^ error: mutable pointer in final value of constant
|
||||
//~| error: encountered `const_allocate` pointer in final value that was not made global
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,16 @@
|
|||
error: encountered `const_allocate` pointer in final value that was not made global
|
||||
--> $DIR/alloc_intrinsic_untyped.rs:8:1
|
||||
|
|
||||
LL | const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 };
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: use `const_make_global` to make allocated pointers immutable before returning
|
||||
|
||||
error: encountered mutable pointer in final value of constant
|
||||
--> $DIR/alloc_intrinsic_untyped.rs:8:1
|
||||
|
|
||||
LL | const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 };
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ const _X: () = unsafe {
|
|||
const Y: &u32 = unsafe {
|
||||
let ptr = intrinsics::const_allocate(4, 4) as *mut u32;
|
||||
*ptr = 42;
|
||||
&*ptr
|
||||
&*(intrinsics::const_make_global(ptr as *mut u8) as *const u32)
|
||||
};
|
||||
|
||||
const Z: &u32 = &42;
|
||||
|
|
|
|||
16
tests/ui/consts/const-eval/heap/make-global-dangling.rs
Normal file
16
tests/ui/consts/const-eval/heap/make-global-dangling.rs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#![feature(core_intrinsics)]
|
||||
#![feature(const_heap)]
|
||||
|
||||
use std::intrinsics;
|
||||
|
||||
const Y: &u32 = unsafe {
|
||||
&*(intrinsics::const_make_global(std::ptr::null_mut()) as *const u32)
|
||||
//~^ error: pointer not dereferenceable
|
||||
};
|
||||
|
||||
const Z: &u32 = unsafe {
|
||||
&*(intrinsics::const_make_global(std::ptr::dangling_mut()) as *const u32)
|
||||
//~^ error: pointer not dereferenceable
|
||||
};
|
||||
|
||||
fn main() {}
|
||||
15
tests/ui/consts/const-eval/heap/make-global-dangling.stderr
Normal file
15
tests/ui/consts/const-eval/heap/make-global-dangling.stderr
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
error[E0080]: pointer not dereferenceable: pointer must point to some allocation, but got null pointer
|
||||
--> $DIR/make-global-dangling.rs:7:8
|
||||
|
|
||||
LL | &*(intrinsics::const_make_global(std::ptr::null_mut()) as *const u32)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `Y` failed here
|
||||
|
||||
error[E0080]: pointer not dereferenceable: pointer must point to some allocation, but got 0x1[noalloc] which is a dangling pointer (it has no provenance)
|
||||
--> $DIR/make-global-dangling.rs:12:8
|
||||
|
|
||||
LL | &*(intrinsics::const_make_global(std::ptr::dangling_mut()) as *const u32)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `Z` failed here
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
13
tests/ui/consts/const-eval/heap/make-global-other.rs
Normal file
13
tests/ui/consts/const-eval/heap/make-global-other.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#![feature(core_intrinsics)]
|
||||
#![feature(const_heap)]
|
||||
|
||||
use std::intrinsics;
|
||||
|
||||
const X: &i32 = &0;
|
||||
|
||||
const Y: &i32 = unsafe {
|
||||
&*(intrinsics::const_make_global(X as *const i32 as *mut u8) as *const i32)
|
||||
//~^ error: pointer passed to `const_make_global` does not point to a heap allocation: ALLOC0<imm>
|
||||
};
|
||||
|
||||
fn main() {}
|
||||
9
tests/ui/consts/const-eval/heap/make-global-other.stderr
Normal file
9
tests/ui/consts/const-eval/heap/make-global-other.stderr
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
error[E0080]: pointer passed to `const_make_global` does not point to a heap allocation: ALLOC0<imm>
|
||||
--> $DIR/make-global-other.rs:9:8
|
||||
|
|
||||
LL | &*(intrinsics::const_make_global(X as *const i32 as *mut u8) as *const i32)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `Y` failed here
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
16
tests/ui/consts/const-eval/heap/make-global-twice.rs
Normal file
16
tests/ui/consts/const-eval/heap/make-global-twice.rs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#![feature(core_intrinsics)]
|
||||
#![feature(const_heap)]
|
||||
|
||||
use std::intrinsics;
|
||||
|
||||
const Y: &i32 = unsafe {
|
||||
let ptr = intrinsics::const_allocate(4, 4);
|
||||
let i = ptr as *mut i32;
|
||||
*i = 20;
|
||||
intrinsics::const_make_global(ptr);
|
||||
intrinsics::const_make_global(ptr);
|
||||
//~^ error: attempting to call `const_make_global` twice on the same allocation ALLOC0
|
||||
&*i
|
||||
};
|
||||
|
||||
fn main() {}
|
||||
9
tests/ui/consts/const-eval/heap/make-global-twice.stderr
Normal file
9
tests/ui/consts/const-eval/heap/make-global-twice.stderr
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
error[E0080]: attempting to call `const_make_global` twice on the same allocation ALLOC0
|
||||
--> $DIR/make-global-twice.rs:11:5
|
||||
|
|
||||
LL | intrinsics::const_make_global(ptr);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `Y` failed here
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
21
tests/ui/consts/const-eval/heap/make-global.rs
Normal file
21
tests/ui/consts/const-eval/heap/make-global.rs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
//@ run-pass
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(const_heap)]
|
||||
use std::intrinsics;
|
||||
|
||||
const FOO: &i32 = foo();
|
||||
const FOO_RAW: *const i32 = foo();
|
||||
|
||||
const fn foo() -> &'static i32 {
|
||||
unsafe {
|
||||
let ptr = intrinsics::const_allocate(4, 4);
|
||||
let t = ptr as *mut i32;
|
||||
*t = 20;
|
||||
intrinsics::const_make_global(ptr);
|
||||
&*t
|
||||
}
|
||||
}
|
||||
fn main() {
|
||||
assert_eq!(*FOO, 20);
|
||||
assert_eq!(unsafe { *FOO_RAW }, 20);
|
||||
}
|
||||
14
tests/ui/consts/const-eval/heap/ptr_made_global_mutated.rs
Normal file
14
tests/ui/consts/const-eval/heap/ptr_made_global_mutated.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#![feature(core_intrinsics)]
|
||||
#![feature(const_heap)]
|
||||
use std::intrinsics;
|
||||
|
||||
const A: &u8 = unsafe {
|
||||
let ptr = intrinsics::const_allocate(1, 1);
|
||||
*ptr = 1;
|
||||
let ptr: *const u8 = intrinsics::const_make_global(ptr);
|
||||
*(ptr as *mut u8) = 2;
|
||||
//~^ error: writing to ALLOC0 which is read-only
|
||||
&*ptr
|
||||
};
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
error[E0080]: writing to ALLOC0 which is read-only
|
||||
--> $DIR/ptr_made_global_mutated.rs:9:5
|
||||
|
|
||||
LL | *(ptr as *mut u8) = 2;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ evaluation of `A` failed here
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
19
tests/ui/consts/const-eval/heap/ptr_not_made_global.rs
Normal file
19
tests/ui/consts/const-eval/heap/ptr_not_made_global.rs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#![feature(core_intrinsics)]
|
||||
#![feature(const_heap)]
|
||||
use std::intrinsics;
|
||||
|
||||
const FOO: &i32 = foo();
|
||||
//~^ error: encountered `const_allocate` pointer in final value that was not made global
|
||||
const FOO_RAW: *const i32 = foo();
|
||||
//~^ error: encountered `const_allocate` pointer in final value that was not made global
|
||||
|
||||
const fn foo() -> &'static i32 {
|
||||
let t = unsafe {
|
||||
let i = intrinsics::const_allocate(4, 4) as *mut i32;
|
||||
*i = 20;
|
||||
i
|
||||
};
|
||||
unsafe { &*t }
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
18
tests/ui/consts/const-eval/heap/ptr_not_made_global.stderr
Normal file
18
tests/ui/consts/const-eval/heap/ptr_not_made_global.stderr
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
error: encountered `const_allocate` pointer in final value that was not made global
|
||||
--> $DIR/ptr_not_made_global.rs:5:1
|
||||
|
|
||||
LL | const FOO: &i32 = foo();
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: use `const_make_global` to make allocated pointers immutable before returning
|
||||
|
||||
error: encountered `const_allocate` pointer in final value that was not made global
|
||||
--> $DIR/ptr_not_made_global.rs:7:1
|
||||
|
|
||||
LL | const FOO_RAW: *const i32 = foo();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: use `const_make_global` to make allocated pointers immutable before returning
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue