Auto merge of #117329 - RalfJung:offset-by-zero, r=oli-obk,scottmcm
offset: allow zero-byte offset on arbitrary pointers As per prior `@rust-lang/opsem` [discussion](https://github.com/rust-lang/opsem-team/issues/10) and [FCP](https://github.com/rust-lang/unsafe-code-guidelines/issues/472#issuecomment-1793409130): - Zero-sized reads and writes are allowed on all sufficiently aligned pointers, including the null pointer - Inbounds-offset-by-zero is allowed on all pointers, including the null pointer - `offset_from` on two pointers derived from the same allocation is always allowed when they have the same address This removes surprising UB (in particular, even C++ allows "nullptr + 0", which we currently disallow), and it brings us one step closer to an important theoretical property for our semantics ("provenance monotonicity": if operations are valid on bytes without provenance, then adding provenance can't make them invalid). The minimum LLVM we require (v17) includes https://reviews.llvm.org/D154051, so we can finally implement this. The `offset_from` change is needed to maintain the equivalence with `offset`: if `let ptr2 = ptr1.offset(N)` is well-defined, then `ptr2.offset_from(ptr1)` should be well-defined and return N. Now consider the case where N is 0 and `ptr1` dangles: we want to still allow offset_from here. I think we should change offset_from further, but that's a separate discussion. Fixes https://github.com/rust-lang/rust/issues/65108 [Tracking issue](https://github.com/rust-lang/rust/issues/117945) | [T-lang summary](https://github.com/rust-lang/rust/pull/117329#issuecomment-1951981106) Cc `@nikic`
This commit is contained in:
commit
5d328a1f62
48 changed files with 202 additions and 476 deletions
|
@ -25,9 +25,9 @@ use rustc_target::spec::abi::Abi as CallAbi;
|
|||
use crate::errors::{LongRunning, LongRunningWarn};
|
||||
use crate::fluent_generated as fluent;
|
||||
use crate::interpret::{
|
||||
self, compile_time_machine, err_ub, throw_exhaust, throw_inval, throw_ub_custom,
|
||||
self, compile_time_machine, err_ub, throw_exhaust, throw_inval, throw_ub_custom, throw_unsup,
|
||||
throw_unsup_format, AllocId, AllocRange, ConstAllocation, CtfeProvenance, FnArg, FnVal, Frame,
|
||||
ImmTy, InterpCx, InterpResult, MPlaceTy, OpTy, Pointer, PointerArithmetic, Scalar,
|
||||
GlobalAlloc, ImmTy, InterpCx, InterpResult, MPlaceTy, OpTy, Pointer, PointerArithmetic, Scalar,
|
||||
};
|
||||
|
||||
use super::error::*;
|
||||
|
@ -759,11 +759,21 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
|||
ecx: &InterpCx<'mir, 'tcx, Self>,
|
||||
alloc_id: AllocId,
|
||||
) -> InterpResult<'tcx> {
|
||||
// Check if this is the currently evaluated static.
|
||||
if Some(alloc_id) == ecx.machine.static_root_ids.map(|(id, _)| id) {
|
||||
Err(ConstEvalErrKind::RecursiveStatic.into())
|
||||
} else {
|
||||
Ok(())
|
||||
return Err(ConstEvalErrKind::RecursiveStatic.into());
|
||||
}
|
||||
// If this is another static, make sure we fire off the query to detect cycles.
|
||||
// But only do that when checks for static recursion are enabled.
|
||||
if ecx.machine.static_root_ids.is_some() {
|
||||
if let Some(GlobalAlloc::Static(def_id)) = ecx.tcx.try_get_global_alloc(alloc_id) {
|
||||
if ecx.tcx.is_foreign_item(def_id) {
|
||||
throw_unsup!(ExternStatic(def_id));
|
||||
}
|
||||
ecx.ctfe_query(|tcx| tcx.eval_static_initializer(def_id))?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue