mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
const-eval: error when initializing a static writes to that static
This commit is contained in:
@@ -352,7 +352,7 @@ const_eval_realloc_or_alloc_with_offset =
|
||||
*[other] {""}
|
||||
} {$ptr} which does not point to the beginning of an object
|
||||
|
||||
const_eval_recursive_static = encountered static that tried to initialize itself with itself
|
||||
const_eval_recursive_static = encountered static that tried to access itself during initialization
|
||||
|
||||
const_eval_remainder_by_zero =
|
||||
calculating the remainder with a divisor of zero
|
||||
|
||||
@@ -62,7 +62,7 @@ pub struct CompileTimeMachine<'tcx> {
|
||||
|
||||
/// If `Some`, we are evaluating the initializer of the static with the given `LocalDefId`,
|
||||
/// storing the result in the given `AllocId`.
|
||||
/// Used to prevent reads from a static's base allocation, as that may allow for self-initialization loops.
|
||||
/// Used to prevent accesses to a static's base allocation, as that may allow for self-initialization loops.
|
||||
pub(crate) static_root_ids: Option<(AllocId, LocalDefId)>,
|
||||
|
||||
/// A cache of "data range" computations for unions (i.e., the offsets of non-padding bytes).
|
||||
@@ -705,19 +705,27 @@ fn before_memory_write(
|
||||
interp_ok(())
|
||||
}
|
||||
|
||||
fn before_alloc_read(ecx: &InterpCx<'tcx, Self>, alloc_id: AllocId) -> InterpResult<'tcx> {
|
||||
fn before_alloc_access(
|
||||
tcx: TyCtxtAt<'tcx>,
|
||||
machine: &Self,
|
||||
alloc_id: AllocId,
|
||||
) -> InterpResult<'tcx> {
|
||||
if machine.stack.is_empty() {
|
||||
// Get out of the way for the final copy.
|
||||
return interp_ok(());
|
||||
}
|
||||
// Check if this is the currently evaluated static.
|
||||
if Some(alloc_id) == ecx.machine.static_root_ids.map(|(id, _)| id) {
|
||||
if Some(alloc_id) == machine.static_root_ids.map(|(id, _)| id) {
|
||||
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) {
|
||||
if machine.static_root_ids.is_some() {
|
||||
if let Some(GlobalAlloc::Static(def_id)) = tcx.try_get_global_alloc(alloc_id) {
|
||||
if tcx.is_foreign_item(def_id) {
|
||||
throw_unsup!(ExternStatic(def_id));
|
||||
}
|
||||
ecx.ctfe_query(|tcx| tcx.eval_static_initializer(def_id))?;
|
||||
tcx.eval_static_initializer(def_id)?;
|
||||
}
|
||||
}
|
||||
interp_ok(())
|
||||
|
||||
@@ -443,7 +443,11 @@ fn before_memory_read(
|
||||
///
|
||||
/// Used to prevent statics from self-initializing by reading from their own memory
|
||||
/// as it is being initialized.
|
||||
fn before_alloc_read(_ecx: &InterpCx<'tcx, Self>, _alloc_id: AllocId) -> InterpResult<'tcx> {
|
||||
fn before_alloc_access(
|
||||
_tcx: TyCtxtAt<'tcx>,
|
||||
_machine: &Self,
|
||||
_alloc_id: AllocId,
|
||||
) -> InterpResult<'tcx> {
|
||||
interp_ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -720,7 +720,7 @@ pub fn get_ptr_alloc<'a>(
|
||||
// do this after `check_and_deref_ptr` to ensure some basic sanity has already been checked.
|
||||
if !self.memory.validation_in_progress.get() {
|
||||
if let Ok((alloc_id, ..)) = self.ptr_try_get_alloc_id(ptr, size_i64) {
|
||||
M::before_alloc_read(self, alloc_id)?;
|
||||
M::before_alloc_access(self.tcx, &self.machine, alloc_id)?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -821,6 +821,9 @@ pub fn get_ptr_alloc_mut<'a>(
|
||||
if let Some((alloc_id, offset, prov, alloc, machine)) = ptr_and_alloc {
|
||||
let range = alloc_range(offset, size);
|
||||
if !validation_in_progress {
|
||||
// For writes, it's okay to only call those when there actually is a non-zero
|
||||
// amount of bytes to be written: a zero-sized write doesn't manifest anything.
|
||||
M::before_alloc_access(tcx, machine, alloc_id)?;
|
||||
M::before_memory_write(
|
||||
tcx,
|
||||
machine,
|
||||
@@ -1396,6 +1399,14 @@ pub fn mem_copy_repeatedly(
|
||||
let src_parts = self.get_ptr_access(src, size)?;
|
||||
let dest_parts = self.get_ptr_access(dest, size * num_copies)?; // `Size` multiplication
|
||||
|
||||
// Similar to `get_ptr_alloc`, we need to call `before_alloc_access` even for zero-sized
|
||||
// reads. However, just like in `get_ptr_alloc_mut`, the write part is okay to skip for
|
||||
// zero-sized writes.
|
||||
if let Ok((alloc_id, ..)) = self.ptr_try_get_alloc_id(src, size.bytes().try_into().unwrap())
|
||||
{
|
||||
M::before_alloc_access(tcx, &self.machine, alloc_id)?;
|
||||
}
|
||||
|
||||
// FIXME: we look up both allocations twice here, once before for the `check_ptr_access`
|
||||
// and once below to get the underlying `&[mut] Allocation`.
|
||||
|
||||
@@ -1408,12 +1419,9 @@ pub fn mem_copy_repeatedly(
|
||||
let src_range = alloc_range(src_offset, size);
|
||||
assert!(!self.memory.validation_in_progress.get(), "we can't be copying during validation");
|
||||
|
||||
// Trigger read hooks.
|
||||
// For the overlapping case, it is crucial that we trigger the read hooks
|
||||
// Trigger read hook.
|
||||
// For the overlapping case, it is crucial that we trigger the read hook
|
||||
// before the write hook -- the aliasing model cares about the order.
|
||||
if let Ok((alloc_id, ..)) = self.ptr_try_get_alloc_id(src, size.bytes() as i64) {
|
||||
M::before_alloc_read(self, alloc_id)?;
|
||||
}
|
||||
M::before_memory_read(
|
||||
tcx,
|
||||
&self.machine,
|
||||
@@ -1438,16 +1446,18 @@ pub fn mem_copy_repeatedly(
|
||||
let provenance = src_alloc
|
||||
.provenance()
|
||||
.prepare_copy(src_range, dest_offset, num_copies, self)
|
||||
.map_err(|e| e.to_interp_error(dest_alloc_id))?;
|
||||
.map_err(|e| e.to_interp_error(src_alloc_id))?;
|
||||
// Prepare a copy of the initialization mask.
|
||||
let init = src_alloc.init_mask().prepare_copy(src_range);
|
||||
|
||||
// Destination alloc preparations and access hooks.
|
||||
let (dest_alloc, extra) = self.get_alloc_raw_mut(dest_alloc_id)?;
|
||||
// Destination alloc preparations...
|
||||
let (dest_alloc, machine) = self.get_alloc_raw_mut(dest_alloc_id)?;
|
||||
let dest_range = alloc_range(dest_offset, size * num_copies);
|
||||
// ...and access hooks.
|
||||
M::before_alloc_access(tcx, machine, dest_alloc_id)?;
|
||||
M::before_memory_write(
|
||||
tcx,
|
||||
extra,
|
||||
machine,
|
||||
&mut dest_alloc.extra,
|
||||
dest,
|
||||
(dest_alloc_id, dest_prov),
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
//! Ensure that writing to `S` while initializing `S` errors.
|
||||
//! Regression test for <https://github.com/rust-lang/rust/issues/142404>.
|
||||
#![allow(dead_code)]
|
||||
|
||||
struct Foo {
|
||||
x: i32,
|
||||
y: (),
|
||||
}
|
||||
|
||||
static S: Foo = Foo {
|
||||
x: 0,
|
||||
y: unsafe {
|
||||
(&raw const S.x).cast_mut().write(1); //~ERROR access itself during initialization
|
||||
},
|
||||
};
|
||||
|
||||
static mut S2: Foo = Foo {
|
||||
x: 0,
|
||||
y: unsafe {
|
||||
S2.x = 1; //~ERROR access itself during initialization
|
||||
},
|
||||
};
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,15 @@
|
||||
error[E0080]: encountered static that tried to access itself during initialization
|
||||
--> $DIR/recursive-static-write.rs:13:9
|
||||
|
|
||||
LL | (&raw const S.x).cast_mut().write(1);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `S` failed here
|
||||
|
||||
error[E0080]: encountered static that tried to access itself during initialization
|
||||
--> $DIR/recursive-static-write.rs:20:9
|
||||
|
|
||||
LL | S2.x = 1;
|
||||
| ^^^^^^^^ evaluation of `S2` failed here
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
@@ -1,20 +1,20 @@
|
||||
error[E0080]: encountered static that tried to initialize itself with itself
|
||||
error[E0080]: encountered static that tried to access itself during initialization
|
||||
--> $DIR/recursive-zst-static.rs:10:18
|
||||
|
|
||||
LL | static FOO: () = FOO;
|
||||
| ^^^ evaluation of `FOO` failed here
|
||||
|
||||
error[E0391]: cycle detected when evaluating initializer of static `A`
|
||||
--> $DIR/recursive-zst-static.rs:13:16
|
||||
--> $DIR/recursive-zst-static.rs:13:1
|
||||
|
|
||||
LL | static A: () = B;
|
||||
| ^
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
note: ...which requires evaluating initializer of static `B`...
|
||||
--> $DIR/recursive-zst-static.rs:14:16
|
||||
--> $DIR/recursive-zst-static.rs:14:1
|
||||
|
|
||||
LL | static B: () = A;
|
||||
| ^
|
||||
| ^^^^^^^^^^^^
|
||||
= note: ...which again requires evaluating initializer of static `A`, completing the cycle
|
||||
= note: cycle used when running analysis passes on this crate
|
||||
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
// See https://github.com/rust-lang/rust/issues/71078 for more details.
|
||||
|
||||
static FOO: () = FOO;
|
||||
//~^ ERROR encountered static that tried to initialize itself with itself
|
||||
//~^ ERROR encountered static that tried to access itself during initialization
|
||||
|
||||
static A: () = B; //~ ERROR cycle detected when evaluating initializer of static `A`
|
||||
static B: () = A;
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
error[E0080]: encountered static that tried to initialize itself with itself
|
||||
error[E0080]: encountered static that tried to access itself during initialization
|
||||
--> $DIR/recursive-zst-static.rs:10:18
|
||||
|
|
||||
LL | static FOO: () = FOO;
|
||||
| ^^^ evaluation of `FOO` failed here
|
||||
|
||||
error[E0391]: cycle detected when evaluating initializer of static `A`
|
||||
--> $DIR/recursive-zst-static.rs:13:16
|
||||
--> $DIR/recursive-zst-static.rs:13:1
|
||||
|
|
||||
LL | static A: () = B;
|
||||
| ^
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
note: ...which requires evaluating initializer of static `B`...
|
||||
--> $DIR/recursive-zst-static.rs:14:16
|
||||
--> $DIR/recursive-zst-static.rs:14:1
|
||||
|
|
||||
LL | static B: () = A;
|
||||
| ^
|
||||
| ^^^^^^^^^^^^
|
||||
= note: ...which again requires evaluating initializer of static `A`, completing the cycle
|
||||
= note: cycle used when running analysis passes on this crate
|
||||
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
//~^ ERROR modifying a static's initial value
|
||||
|
||||
pub static mut C: u32 = unsafe { C = 1; 0 };
|
||||
//~^ ERROR static that tried to access itself during initialization
|
||||
|
||||
pub static D: u32 = D;
|
||||
//~^ ERROR static that tried to initialize itself with itself
|
||||
//~^ ERROR static that tried to access itself during initialization
|
||||
|
||||
fn main() {}
|
||||
|
||||
@@ -4,12 +4,18 @@ error[E0080]: modifying a static's initial value from another static's initializ
|
||||
LL | pub static mut B: () = unsafe { A = 1; };
|
||||
| ^^^^^ evaluation of `B` failed here
|
||||
|
||||
error[E0080]: encountered static that tried to initialize itself with itself
|
||||
--> $DIR/write-to-static-mut-in-static.rs:7:21
|
||||
error[E0080]: encountered static that tried to access itself during initialization
|
||||
--> $DIR/write-to-static-mut-in-static.rs:5:34
|
||||
|
|
||||
LL | pub static mut C: u32 = unsafe { C = 1; 0 };
|
||||
| ^^^^^ evaluation of `C` failed here
|
||||
|
||||
error[E0080]: encountered static that tried to access itself during initialization
|
||||
--> $DIR/write-to-static-mut-in-static.rs:8:21
|
||||
|
|
||||
LL | pub static D: u32 = D;
|
||||
| ^ evaluation of `D` failed here
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
pub static FOO: u32 = FOO;
|
||||
//~^ ERROR encountered static that tried to initialize itself with itself
|
||||
//~^ ERROR encountered static that tried to access itself during initialization
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub union Foo {
|
||||
@@ -7,6 +7,6 @@ pub union Foo {
|
||||
}
|
||||
|
||||
pub static BAR: Foo = BAR;
|
||||
//~^ ERROR encountered static that tried to initialize itself with itself
|
||||
//~^ ERROR encountered static that tried to access itself during initialization
|
||||
|
||||
fn main() {}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
error[E0080]: encountered static that tried to initialize itself with itself
|
||||
error[E0080]: encountered static that tried to access itself during initialization
|
||||
--> $DIR/recursive-static-definition.rs:1:23
|
||||
|
|
||||
LL | pub static FOO: u32 = FOO;
|
||||
| ^^^ evaluation of `FOO` failed here
|
||||
|
||||
error[E0080]: encountered static that tried to initialize itself with itself
|
||||
error[E0080]: encountered static that tried to access itself during initialization
|
||||
--> $DIR/recursive-static-definition.rs:9:23
|
||||
|
|
||||
LL | pub static BAR: Foo = BAR;
|
||||
|
||||
@@ -8,13 +8,15 @@
|
||||
|
||||
use std::mem::MaybeUninit;
|
||||
|
||||
pub static X: (i32, MaybeUninit<i32>) = (1, foo(&X.0));
|
||||
//~^ ERROR: encountered static that tried to initialize itself with itself
|
||||
pub static X: (i32, MaybeUninit<i32>) = (1, foo(&X.0, 1));
|
||||
//~^ ERROR: encountered static that tried to access itself during initialization
|
||||
pub static Y: (i32, MaybeUninit<i32>) = (1, foo(&Y.0, 0));
|
||||
//~^ ERROR: encountered static that tried to access itself during initialization
|
||||
|
||||
const fn foo(x: &i32) -> MaybeUninit<i32> {
|
||||
const fn foo(x: &i32, num: usize) -> MaybeUninit<i32> {
|
||||
let mut temp = MaybeUninit::<i32>::uninit();
|
||||
unsafe {
|
||||
std::ptr::copy(x, temp.as_mut_ptr(), 1);
|
||||
std::ptr::copy(x, temp.as_mut_ptr(), num);
|
||||
}
|
||||
temp
|
||||
}
|
||||
|
||||
@@ -1,17 +1,31 @@
|
||||
error[E0080]: encountered static that tried to initialize itself with itself
|
||||
error[E0080]: encountered static that tried to access itself during initialization
|
||||
--> $DIR/read_before_init.rs:11:45
|
||||
|
|
||||
LL | pub static X: (i32, MaybeUninit<i32>) = (1, foo(&X.0));
|
||||
| ^^^^^^^^^ evaluation of `X` failed inside this call
|
||||
LL | pub static X: (i32, MaybeUninit<i32>) = (1, foo(&X.0, 1));
|
||||
| ^^^^^^^^^^^^ evaluation of `X` failed inside this call
|
||||
|
|
||||
note: inside `foo`
|
||||
--> $DIR/read_before_init.rs:17:9
|
||||
--> $DIR/read_before_init.rs:19:9
|
||||
|
|
||||
LL | std::ptr::copy(x, temp.as_mut_ptr(), 1);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | std::ptr::copy(x, temp.as_mut_ptr(), num);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
note: inside `std::ptr::copy::<i32>`
|
||||
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
error[E0080]: encountered static that tried to access itself during initialization
|
||||
--> $DIR/read_before_init.rs:13:45
|
||||
|
|
||||
LL | pub static Y: (i32, MaybeUninit<i32>) = (1, foo(&Y.0, 0));
|
||||
| ^^^^^^^^^^^^ evaluation of `Y` failed inside this call
|
||||
|
|
||||
note: inside `foo`
|
||||
--> $DIR/read_before_init.rs:19:9
|
||||
|
|
||||
LL | std::ptr::copy(x, temp.as_mut_ptr(), num);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
note: inside `std::ptr::copy::<i32>`
|
||||
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
|
||||
Reference in New Issue
Block a user