From 22364f86aeba440066db931132ecee8292b709fd Mon Sep 17 00:00:00 2001 From: Neven Villani Date: Tue, 9 Jul 2024 14:24:05 +0200 Subject: [PATCH 01/33] This pattern using lazy protected Reserved IM prevents spurious writes --- .../tree_borrows/reservedim_spurious_write.rs | 109 ++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs diff --git a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs new file mode 100644 index 0000000000000..1f52537f9a295 --- /dev/null +++ b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs @@ -0,0 +1,109 @@ +// Illustrating a problematic interaction between Reserved, interior mutability, +// and protectors, that makes spurious writes fail in the previous model of Tree Borrows. +// As for all similar tests, we disable preemption so that the error message is deterministic. +//@compile-flags: -Zmiri-tree-borrows -Zmiri-preemption-rate=0 + +use std::cell::Cell; +use std::sync::{Arc, Barrier}; +use std::thread; + +// Here is the problematic interleaving: +// - thread 1: retag and activate `x` (protected) +// - thread 2: create but do not retag (lazy) `y` as Reserved with interior mutability +// - thread 1: spurious write through `x` would go here +// - thread 2: function exit (noop due to lazyness) +// - thread 1: function exit (no permanent effect on `y` because it is now Reserved IM unprotected) +// - thread 2: write through `y` +// In the source code nothing happens to `y` + +// `Send`able raw pointer wrapper. +#[derive(Copy, Clone)] +struct SendPtr(*mut u8); +unsafe impl Send for SendPtr {} + +type IdxBarrier = (usize, Arc); + +// Barriers to enforce the interleaving. +// This macro expects `synchronized!(thread, msg)` where `thread` is a `IdxBarrier`, +// and `msg` is the message to be displayed when the thread reaches this point in the execution. +macro_rules! synchronized { + ($thread:expr, $msg:expr) => {{ + let (thread_id, barrier) = &$thread; + eprintln!("Thread {} executing: {}", thread_id, $msg); + barrier.wait(); + }}; +} + +fn main() { + eprintln!("Without spurious write"); + example(false); + + eprintln!("\nIf this text is visible then the model forbids spurious writes.\n"); + + eprintln!("With spurious write"); + example(true); + + eprintln!("\nIf this text is visible then the model fails to detect a noalias violation.\n"); +} + +fn example(spurious: bool) { + // For this example it is important that we have at least two bytes + // because lazyness is involved. + let mut data = [0u8; 2]; + let ptr = SendPtr(std::ptr::addr_of_mut!(data[0])); + let barrier = Arc::new(Barrier::new(2)); + let bx = Arc::clone(&barrier); + let by = Arc::clone(&barrier); + + // Retag and activate `x`, wait until the other thread creates a lazy permission. + // Then do a spurious write. Finally exit the function after the other thread. + let thread_1 = thread::spawn(move || { + let b = (1, bx); + synchronized!(b, "start"); + let ptr = ptr; + synchronized!(b, "retag x (&mut, protect)"); + fn inner(x: &mut u8, b: IdxBarrier, spurious: bool) { + *x = 42; // activate immediately + synchronized!(b, "[lazy] retag y (&mut, protect, IM)"); + // A spurious write should be valid here because `x` is + // `Active` and protected. + if spurious { + synchronized!(b, "spurious write x (executed)"); + *x = 64; + } else { + synchronized!(b, "spurious write x (skipped)"); + } + synchronized!(b, "ret y"); + synchronized!(b, "ret x"); + } + inner(unsafe { &mut *ptr.0 }, b.clone(), spurious); + synchronized!(b, "write y"); + synchronized!(b, "end"); + }); + + // Create a lazy Reserved with interior mutability. + // Wait for the other thread's spurious write then observe the side effects + // of that write. + let thread_2 = thread::spawn(move || { + let b = (2, by); + synchronized!(b, "start"); + let ptr = ptr; + synchronized!(b, "retag x (&mut, protect)"); + synchronized!(b, "[lazy] retag y (&mut, protect, IM)"); + fn inner(y: &mut Cell, b: IdxBarrier) -> *mut u8 { + synchronized!(b, "spurious write x"); + synchronized!(b, "ret y"); + y as *mut Cell as *mut u8 + } + // Currently `ptr` points to `data[0]`. We retag it for `data[1]` + // then use it for `data[0]` where its initialization has been deferred. + let y = inner(unsafe { &mut *(ptr.0 as *mut Cell).wrapping_add(1) }, b.clone()); + synchronized!(b, "ret x"); + synchronized!(b, "write y"); + unsafe { *y.wrapping_sub(1) = 13 } + synchronized!(b, "end"); + }); + + thread_1.join().unwrap(); + thread_2.join().unwrap(); +} From 2de6e7f3a680a8000f83f2b62252d18a1bb06966 Mon Sep 17 00:00:00 2001 From: Neven Villani Date: Tue, 9 Jul 2024 14:36:46 +0200 Subject: [PATCH 02/33] Implement fix for reservedim_spurious_write: ignore IM on protected --- .../src/borrow_tracker/tree_borrows/mod.rs | 10 ++++- .../src/borrow_tracker/tree_borrows/perms.rs | 5 +++ .../reserved/cell-protected-write.stderr | 6 +-- .../tree_borrows/reservedim_spurious_write.rs | 2 +- .../reservedim_spurious_write.stderr | 41 +++++++++++++++++++ .../tests/pass/tree_borrows/reserved.stderr | 2 +- 6 files changed, 59 insertions(+), 7 deletions(-) create mode 100644 src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.stderr 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 86074384084d5..4d9595b352f28 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -141,8 +141,14 @@ impl<'tcx> NewPermission { ) -> Option { let ty_is_freeze = pointee.is_freeze(*cx.tcx, cx.param_env()); let ty_is_unpin = pointee.is_unpin(*cx.tcx, cx.param_env()); + let is_protected = kind == RetagKind::FnEntry; + // As demonstrated by `tests/fail/tree_borrows/reservedim_spurious_write.rs`, + // interior mutability and protectors interact poorly. + // To eliminate the case of Protected Reserved IM we override interior mutability + // in the case of a protected reference. let initial_state = match mutability { - Mutability::Mut if ty_is_unpin => Permission::new_reserved(ty_is_freeze), + Mutability::Mut if ty_is_unpin => + Permission::new_reserved(ty_is_freeze || is_protected), Mutability::Not if ty_is_freeze => Permission::new_frozen(), // Raw pointers never enter this function so they are not handled. // However raw pointers are not the only pointers that take the parent @@ -151,7 +157,7 @@ impl<'tcx> NewPermission { _ => return None, }; - let protector = (kind == RetagKind::FnEntry).then_some(ProtectorKind::StrongProtector); + let protector = is_protected.then_some(ProtectorKind::StrongProtector); Some(Self { zero_size: false, initial_state, protector }) } diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs index 7aa9c3e862bcc..9c19ae76a2d01 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs @@ -22,6 +22,11 @@ enum PermissionPriv { /// - foreign-read then child-write is UB due to `conflicted`, /// - child-write then foreign-read is UB since child-write will activate and then /// foreign-read disables a protected `Active`, which is UB. + /// + /// Note: since the discovery of `tests/fail/tree_borrows/reservedim_spurious_write.rs`, + /// `ty_is_freeze` does not strictly mean that the type has no interior mutability, + /// it could be an interior mutable type that lost its interior mutability privileges + /// when retagged with a protector. Reserved { ty_is_freeze: bool, conflicted: bool }, /// represents: a unique pointer; /// allows: child reads, child writes; diff --git a/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr b/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr index 7d000ba55e60b..ce9a5b7f15865 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr @@ -5,7 +5,7 @@ Warning: this tree is indicative only. Some tags may have been hidden. | RsM | └─┬── | RsM | ├─┬── | RsM | │ └─┬── -| RsM | │ └──── Strongly protected +| Rs | │ └──── Strongly protected | RsM | └──── ────────────────────────────────────────────────── error: Undefined Behavior: write access through (y, callee:y, caller:y) at ALLOC[0x0] is forbidden @@ -16,14 +16,14 @@ LL | *y = 1; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag (y, callee:y, caller:y) is foreign to the protected tag (callee:x) (i.e., it is not a child) - = help: this foreign write access would cause the protected tag (callee:x) (currently Reserved (interior mutable)) to become Disabled + = help: this foreign write access would cause the protected tag (callee:x) (currently Reserved) to become Disabled = help: protected tags must never be Disabled help: the accessed tag was created here --> $DIR/cell-protected-write.rs:LL:CC | LL | let y = (&mut *n).get(); | ^^^^^^^^^ -help: the protected tag was created here, in the initial state Reserved (interior mutable) +help: the protected tag was created here, in the initial state Reserved --> $DIR/cell-protected-write.rs:LL:CC | LL | unsafe fn write_second(x: &mut UnsafeCell, y: *mut u8) { diff --git a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs index 1f52537f9a295..5e7cb5e34cc2b 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs +++ b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs @@ -100,7 +100,7 @@ fn example(spurious: bool) { let y = inner(unsafe { &mut *(ptr.0 as *mut Cell).wrapping_add(1) }, b.clone()); synchronized!(b, "ret x"); synchronized!(b, "write y"); - unsafe { *y.wrapping_sub(1) = 13 } + unsafe { *y.wrapping_sub(1) = 13 } //~ERROR: /write access through .* is forbidden/ synchronized!(b, "end"); }); diff --git a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.stderr b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.stderr new file mode 100644 index 0000000000000..9be6c157c0cbb --- /dev/null +++ b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.stderr @@ -0,0 +1,41 @@ +Without spurious write +Thread 1 executing: start +Thread 2 executing: start +Thread 2 executing: retag x (&mut, protect) +Thread 1 executing: retag x (&mut, protect) +Thread 1 executing: [lazy] retag y (&mut, protect, IM) +Thread 2 executing: [lazy] retag y (&mut, protect, IM) +Thread 2 executing: spurious write x +Thread 1 executing: spurious write x (skipped) +Thread 1 executing: ret y +Thread 2 executing: ret y +Thread 2 executing: ret x +Thread 1 executing: ret x +Thread 1 executing: write y +Thread 2 executing: write y +error: Undefined Behavior: write access through at ALLOC[0x0] is forbidden + --> $DIR/reservedim_spurious_write.rs:LL:CC + | +LL | unsafe { *y.wrapping_sub(1) = 13 } + | ^^^^^^^^^^^^^^^^^^^^^^^ write access through at ALLOC[0x0] is forbidden + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: the accessed tag has state Disabled which forbids this child write access +help: the accessed tag was created here, in the initial state Reserved + --> $DIR/reservedim_spurious_write.rs:LL:CC + | +LL | fn inner(y: &mut Cell, b: IdxBarrier) -> *mut u8 { + | ^ +help: the accessed tag later transitioned to Disabled due to a protector release (acting as a foreign write access) on every location previously accessed by this tag + --> $DIR/reservedim_spurious_write.rs:LL:CC + | +LL | } + | ^ + = help: this transition corresponds to a loss of read and write permissions + = note: BACKTRACE (of the first span) on thread `unnamed-ID`: + = note: inside closure at $DIR/reservedim_spurious_write.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/pass/tree_borrows/reserved.stderr b/src/tools/miri/tests/pass/tree_borrows/reserved.stderr index 0d0d52c717fed..d149a4065f92b 100644 --- a/src/tools/miri/tests/pass/tree_borrows/reserved.stderr +++ b/src/tools/miri/tests/pass/tree_borrows/reserved.stderr @@ -6,7 +6,7 @@ Warning: this tree is indicative only. Some tags may have been hidden. | RsM | └─┬── | RsM | ├─┬── | RsM | │ └─┬── -| RsCM| │ └──── +| RsC | │ └──── | RsM | └──── ────────────────────────────────────────────────── [interior mut] Foreign Read: Re* -> Re* From 22996ad073870c5ac7753ba1acbaba784adc534d Mon Sep 17 00:00:00 2001 From: Neven Villani Date: Tue, 9 Jul 2024 19:42:12 +0200 Subject: [PATCH 03/33] Apply suggestions - split test into two revisions - clarify comments --- .../src/borrow_tracker/tree_borrows/mod.rs | 3 +- .../tree_borrows/reservedim_spurious_write.rs | 26 +++++------- .../reservedim_spurious_write.with.stderr | 40 +++++++++++++++++++ ... reservedim_spurious_write.without.stderr} | 1 - 4 files changed, 52 insertions(+), 18 deletions(-) create mode 100644 src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.with.stderr rename src/tools/miri/tests/fail/tree_borrows/{reservedim_spurious_write.stderr => reservedim_spurious_write.without.stderr} (98%) 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 4d9595b352f28..123d4b407fb4c 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -145,7 +145,8 @@ impl<'tcx> NewPermission { // As demonstrated by `tests/fail/tree_borrows/reservedim_spurious_write.rs`, // interior mutability and protectors interact poorly. // To eliminate the case of Protected Reserved IM we override interior mutability - // in the case of a protected reference. + // in the case of a protected reference: protected references are always considered + // "freeze". let initial_state = match mutability { Mutability::Mut if ty_is_unpin => Permission::new_reserved(ty_is_freeze || is_protected), diff --git a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs index 5e7cb5e34cc2b..611f64dce5e50 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs +++ b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs @@ -2,6 +2,12 @@ // and protectors, that makes spurious writes fail in the previous model of Tree Borrows. // As for all similar tests, we disable preemption so that the error message is deterministic. //@compile-flags: -Zmiri-tree-borrows -Zmiri-preemption-rate=0 +// +// One revision without spurious read (default source code) and one with spurious read. +// Both are expected to be UB. Both revisions are expected to have the *same* error +// because we are aligning the behavior of `without` to that of `with` so that the +// spurious write is effectively a noop in the long term. +//@revisions: without with use std::cell::Cell; use std::sync::{Arc, Barrier}; @@ -9,7 +15,7 @@ use std::thread; // Here is the problematic interleaving: // - thread 1: retag and activate `x` (protected) -// - thread 2: create but do not retag (lazy) `y` as Reserved with interior mutability +// - thread 2: retag but do not initialize (lazy) `y` as Reserved with interior mutability // - thread 1: spurious write through `x` would go here // - thread 2: function exit (noop due to lazyness) // - thread 1: function exit (no permanent effect on `y` because it is now Reserved IM unprotected) @@ -35,18 +41,6 @@ macro_rules! synchronized { } fn main() { - eprintln!("Without spurious write"); - example(false); - - eprintln!("\nIf this text is visible then the model forbids spurious writes.\n"); - - eprintln!("With spurious write"); - example(true); - - eprintln!("\nIf this text is visible then the model fails to detect a noalias violation.\n"); -} - -fn example(spurious: bool) { // For this example it is important that we have at least two bytes // because lazyness is involved. let mut data = [0u8; 2]; @@ -62,12 +56,12 @@ fn example(spurious: bool) { synchronized!(b, "start"); let ptr = ptr; synchronized!(b, "retag x (&mut, protect)"); - fn inner(x: &mut u8, b: IdxBarrier, spurious: bool) { + fn inner(x: &mut u8, b: IdxBarrier) { *x = 42; // activate immediately synchronized!(b, "[lazy] retag y (&mut, protect, IM)"); // A spurious write should be valid here because `x` is // `Active` and protected. - if spurious { + if cfg!(with) { synchronized!(b, "spurious write x (executed)"); *x = 64; } else { @@ -76,7 +70,7 @@ fn example(spurious: bool) { synchronized!(b, "ret y"); synchronized!(b, "ret x"); } - inner(unsafe { &mut *ptr.0 }, b.clone(), spurious); + inner(unsafe { &mut *ptr.0 }, b.clone()); synchronized!(b, "write y"); synchronized!(b, "end"); }); diff --git a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.with.stderr b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.with.stderr new file mode 100644 index 0000000000000..5ac9c912ba9ee --- /dev/null +++ b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.with.stderr @@ -0,0 +1,40 @@ +Thread 1 executing: start +Thread 2 executing: start +Thread 2 executing: retag x (&mut, protect) +Thread 1 executing: retag x (&mut, protect) +Thread 1 executing: [lazy] retag y (&mut, protect, IM) +Thread 2 executing: [lazy] retag y (&mut, protect, IM) +Thread 2 executing: spurious write x +Thread 1 executing: spurious write x (executed) +Thread 1 executing: ret y +Thread 2 executing: ret y +Thread 2 executing: ret x +Thread 1 executing: ret x +Thread 1 executing: write y +Thread 2 executing: write y +error: Undefined Behavior: write access through at ALLOC[0x0] is forbidden + --> $DIR/reservedim_spurious_write.rs:LL:CC + | +LL | unsafe { *y.wrapping_sub(1) = 13 } + | ^^^^^^^^^^^^^^^^^^^^^^^ write access through at ALLOC[0x0] is forbidden + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: the accessed tag has state Disabled which forbids this child write access +help: the accessed tag was created here, in the initial state Reserved + --> $DIR/reservedim_spurious_write.rs:LL:CC + | +LL | fn inner(y: &mut Cell, b: IdxBarrier) -> *mut u8 { + | ^ +help: the accessed tag later transitioned to Disabled due to a foreign write access at offsets [0x0..0x1] + --> $DIR/reservedim_spurious_write.rs:LL:CC + | +LL | *x = 64; + | ^^^^^^^ + = help: this transition corresponds to a loss of read and write permissions + = note: BACKTRACE (of the first span) on thread `unnamed-ID`: + = note: inside closure at $DIR/reservedim_spurious_write.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.stderr b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.without.stderr similarity index 98% rename from src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.stderr rename to src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.without.stderr index 9be6c157c0cbb..97c71fdedefb3 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.without.stderr @@ -1,4 +1,3 @@ -Without spurious write Thread 1 executing: start Thread 2 executing: start Thread 2 executing: retag x (&mut, protect) From 68aed4a5cebf846d88716489e4ea66074d669c5b Mon Sep 17 00:00:00 2001 From: Neven Villani Date: Wed, 10 Jul 2024 14:32:02 +0200 Subject: [PATCH 04/33] Second byte is not involved in the example; use a Cell<()> instead --- .../tree_borrows/reservedim_spurious_write.rs | 23 +++++++++++-------- .../reservedim_spurious_write.with.stderr | 6 ++--- .../reservedim_spurious_write.without.stderr | 6 ++--- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs index 611f64dce5e50..6ae79be6cc7e8 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs +++ b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs @@ -41,10 +41,10 @@ macro_rules! synchronized { } fn main() { - // For this example it is important that we have at least two bytes - // because lazyness is involved. - let mut data = [0u8; 2]; - let ptr = SendPtr(std::ptr::addr_of_mut!(data[0])); + // The conflict occurs one one single location but the example involves + // lazily initialized permissions. + let mut data = 0u8; + let ptr = SendPtr(std::ptr::addr_of_mut!(data)); let barrier = Arc::new(Barrier::new(2)); let bx = Arc::clone(&barrier); let by = Arc::clone(&barrier); @@ -84,17 +84,20 @@ fn main() { let ptr = ptr; synchronized!(b, "retag x (&mut, protect)"); synchronized!(b, "[lazy] retag y (&mut, protect, IM)"); - fn inner(y: &mut Cell, b: IdxBarrier) -> *mut u8 { + fn inner(y: &mut Cell<()>, b: IdxBarrier) -> *mut u8 { synchronized!(b, "spurious write x"); synchronized!(b, "ret y"); - y as *mut Cell as *mut u8 + // `y` is not retagged for any bytes, so the pointer we return + // has its permission lazily initialized. + y as *mut Cell<()> as *mut u8 } - // Currently `ptr` points to `data[0]`. We retag it for `data[1]` - // then use it for `data[0]` where its initialization has been deferred. - let y = inner(unsafe { &mut *(ptr.0 as *mut Cell).wrapping_add(1) }, b.clone()); + // Currently `ptr` points to `data`. + // We do a zero-sized retag so that its permission is lazy. + let y_zst = unsafe { &mut *(ptr.0 as *mut Cell<()>) }; + let y = inner(y_zst, b.clone()); synchronized!(b, "ret x"); synchronized!(b, "write y"); - unsafe { *y.wrapping_sub(1) = 13 } //~ERROR: /write access through .* is forbidden/ + unsafe { *y = 13 } //~ERROR: /write access through .* is forbidden/ synchronized!(b, "end"); }); diff --git a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.with.stderr b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.with.stderr index 5ac9c912ba9ee..0e4517e90105c 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.with.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.with.stderr @@ -15,15 +15,15 @@ Thread 2 executing: write y error: Undefined Behavior: write access through at ALLOC[0x0] is forbidden --> $DIR/reservedim_spurious_write.rs:LL:CC | -LL | unsafe { *y.wrapping_sub(1) = 13 } - | ^^^^^^^^^^^^^^^^^^^^^^^ write access through at ALLOC[0x0] is forbidden +LL | unsafe { *y = 13 } + | ^^^^^^^ write access through at ALLOC[0x0] is forbidden | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag has state Disabled which forbids this child write access help: the accessed tag was created here, in the initial state Reserved --> $DIR/reservedim_spurious_write.rs:LL:CC | -LL | fn inner(y: &mut Cell, b: IdxBarrier) -> *mut u8 { +LL | fn inner(y: &mut Cell<()>, b: IdxBarrier) -> *mut u8 { | ^ help: the accessed tag later transitioned to Disabled due to a foreign write access at offsets [0x0..0x1] --> $DIR/reservedim_spurious_write.rs:LL:CC diff --git a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.without.stderr b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.without.stderr index 97c71fdedefb3..cbeef90243bfb 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.without.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.without.stderr @@ -15,15 +15,15 @@ Thread 2 executing: write y error: Undefined Behavior: write access through at ALLOC[0x0] is forbidden --> $DIR/reservedim_spurious_write.rs:LL:CC | -LL | unsafe { *y.wrapping_sub(1) = 13 } - | ^^^^^^^^^^^^^^^^^^^^^^^ write access through at ALLOC[0x0] is forbidden +LL | unsafe { *y = 13 } + | ^^^^^^^ write access through at ALLOC[0x0] is forbidden | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental = help: the accessed tag has state Disabled which forbids this child write access help: the accessed tag was created here, in the initial state Reserved --> $DIR/reservedim_spurious_write.rs:LL:CC | -LL | fn inner(y: &mut Cell, b: IdxBarrier) -> *mut u8 { +LL | fn inner(y: &mut Cell<()>, b: IdxBarrier) -> *mut u8 { | ^ help: the accessed tag later transitioned to Disabled due to a protector release (acting as a foreign write access) on every location previously accessed by this tag --> $DIR/reservedim_spurious_write.rs:LL:CC From 78f6386b623c64160fa3475605c7ebfb065f62bf Mon Sep 17 00:00:00 2001 From: Neven Villani Date: Fri, 12 Jul 2024 10:51:32 +0200 Subject: [PATCH 05/33] Clarify comment in tests/fail/tree_borrows/reservedim_spurious_write.rs Co-authored-by: Ralf Jung --- .../tests/fail/tree_borrows/reservedim_spurious_write.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs index 6ae79be6cc7e8..73f227fee2fcb 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs +++ b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs @@ -41,8 +41,9 @@ macro_rules! synchronized { } fn main() { - // The conflict occurs one one single location but the example involves - // lazily initialized permissions. + // The conflict occurs on one single location but the example involves + // lazily initialized permissions. We will use `&mut Cell<()>` references + // to `data` to achieve this. let mut data = 0u8; let ptr = SendPtr(std::ptr::addr_of_mut!(data)); let barrier = Arc::new(Barrier::new(2)); From fd81880c9108c4b98839d55fe29884a625f05f02 Mon Sep 17 00:00:00 2001 From: Neven Villani Date: Fri, 12 Jul 2024 15:58:59 +0200 Subject: [PATCH 06/33] Leave a trace of the current suboptimal status of foreign_write --- src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs index 9c19ae76a2d01..8e23257b6c006 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs @@ -146,6 +146,12 @@ mod transition { /// non-protected interior mutable `Reserved` which stay the same. fn foreign_write(state: PermissionPriv, protected: bool) -> Option { Some(match state { + // FIXME: since the fix related to reservedim_spurious_write, it is now possible + // to express these transitions of the state machine without an explicit dependency + // on `protected`: because `ty_is_freeze: false` implies `!protected` then + // the line handling `Reserved { .. } if protected` could be deleted. + // This will however require optimizations to the exhaustive tests because + // fewer initial conditions are valid. Reserved { .. } if protected => Disabled, res @ Reserved { ty_is_freeze: false, .. } => res, _ => Disabled, From e1e5b8a2b69da18b11147aa8d18e731ee32d9819 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Tue, 16 Jul 2024 05:14:32 +0000 Subject: [PATCH 07/33] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index e90d3732ca577..2c29af8b9357f 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -99b7134389e9766462601a2fc4013840b9d31745 +5c8488605624d67b272953bc21d41db60dbd5654 From e5544dc087acc760d987781f48680ce505c1855f Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Sat, 20 Jul 2024 05:04:25 +0000 Subject: [PATCH 08/33] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 2c29af8b9357f..b09d4f11f68ef 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -5c8488605624d67b272953bc21d41db60dbd5654 +9057c3ffec44926d5e149dc13ff3ce1613b69cce From 69b9eab4aba6d13c348e09190785fa9c015baae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Mon, 22 Jul 2024 16:51:20 +0300 Subject: [PATCH 09/33] Add `O_NOFOLLOW` flag support --- src/tools/miri/src/shims/unix/fs.rs | 29 +++++++++++++++++-- ...libc-fs-readlink.rs => libc-fs-symlink.rs} | 20 +++++++++++++ src/tools/miri/tests/pass-dep/libc/libc-fs.rs | 9 ++++++ 3 files changed, 55 insertions(+), 3 deletions(-) rename src/tools/miri/tests/pass-dep/libc/{libc-fs-readlink.rs => libc-fs-symlink.rs} (76%) diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index e34aa5c09dfe1..d1218114e0d7a 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -266,7 +266,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); - let path = this.read_pointer(&args[0])?; + let path_raw = this.read_pointer(&args[0])?; + let path = this.read_path_from_c_str(path_raw)?; let flag = this.read_scalar(&args[1])?.to_i32()?; let mut options = OpenOptions::new(); @@ -366,14 +367,36 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { return Ok(-1); } } + + let o_nofollow = this.eval_libc_i32("O_NOFOLLOW"); + if flag & o_nofollow == o_nofollow { + #[cfg(unix)] + { + use std::os::unix::fs::OpenOptionsExt; + options.custom_flags(libc::O_NOFOLLOW); + } + // Strictly speaking, this emulation is not equivalent to the O_NOFOLLOW flag behavior: + // the path could change between us checking it here and the later call to `open`. + // But it's good enough for Miri purposes. + #[cfg(not(unix))] + { + // O_NOFOLLOW only fails when the trailing component is a symlink; + // the entire rest of the path can still contain symlinks. + if path.is_symlink() { + let eloop = this.eval_libc("ELOOP"); + this.set_last_error(eloop)?; + return Ok(-1); + } + } + mirror |= o_nofollow; + } + // If `flag` is not equal to `mirror`, there is an unsupported option enabled in `flag`, // then we throw an error. if flag != mirror { throw_unsup_format!("unsupported flags {:#x}", flag & !mirror); } - let path = this.read_path_from_c_str(path)?; - // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`open`", reject_with)?; diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs-readlink.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs-symlink.rs similarity index 76% rename from src/tools/miri/tests/pass-dep/libc/libc-fs-readlink.rs rename to src/tools/miri/tests/pass-dep/libc/libc-fs-symlink.rs index d72edd7d9e3f2..96ced05cd1e8e 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-fs-readlink.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-fs-symlink.rs @@ -11,6 +11,11 @@ use std::os::unix::ffi::OsStrExt; mod utils; fn main() { + test_readlink(); + test_nofollow_symlink(); +} + +fn test_readlink() { let bytes = b"Hello, World!\n"; let path = utils::prepare_with_content("miri_test_fs_link_target.txt", bytes); let expected_path = path.as_os_str().as_bytes(); @@ -49,3 +54,18 @@ fn main() { assert_eq!(res, -1); assert_eq!(Error::last_os_error().kind(), ErrorKind::NotFound); } + +fn test_nofollow_symlink() { + let bytes = b"Hello, World!\n"; + let path = utils::prepare_with_content("test_nofollow_symlink_target.txt", bytes); + + let symlink_path = utils::prepare("test_nofollow_symlink.txt"); + std::os::unix::fs::symlink(&path, &symlink_path).unwrap(); + + let symlink_cpath = CString::new(symlink_path.as_os_str().as_bytes()).unwrap(); + + let ret = unsafe { libc::open(symlink_cpath.as_ptr(), libc::O_NOFOLLOW | libc::O_CLOEXEC) }; + assert_eq!(ret, -1); + let err = io::Error::last_os_error().raw_os_error().unwrap(); + assert_eq!(err, libc::ELOOP); +} diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs index eddea92353e3d..5b2bbfbb27d08 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs @@ -37,6 +37,7 @@ fn main() { test_sync_file_range(); test_isatty(); test_read_and_uninit(); + test_nofollow_not_symlink(); } fn test_file_open_unix_allow_two_args() { @@ -423,3 +424,11 @@ fn test_read_and_uninit() { remove_file(&path).unwrap(); } } + +fn test_nofollow_not_symlink() { + let bytes = b"Hello, World!\n"; + let path = utils::prepare_with_content("test_nofollow_not_symlink.txt", bytes); + let cpath = CString::new(path.as_os_str().as_bytes()).unwrap(); + let ret = unsafe { libc::open(cpath.as_ptr(), libc::O_NOFOLLOW | libc::O_CLOEXEC) }; + assert!(ret >= 0); +} From 06a14f1990d9baf984a4162c32c54f707d317114 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Mon, 22 Jul 2024 17:01:11 +0300 Subject: [PATCH 10/33] Fix test --- src/tools/miri/tests/pass-dep/libc/libc-fs-symlink.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs-symlink.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs-symlink.rs index 96ced05cd1e8e..619c6db3a29de 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-fs-symlink.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-fs-symlink.rs @@ -66,6 +66,6 @@ fn test_nofollow_symlink() { let ret = unsafe { libc::open(symlink_cpath.as_ptr(), libc::O_NOFOLLOW | libc::O_CLOEXEC) }; assert_eq!(ret, -1); - let err = io::Error::last_os_error().raw_os_error().unwrap(); + let err = Error::last_os_error().raw_os_error().unwrap(); assert_eq!(err, libc::ELOOP); } From 56d672e8f7605af25dcce6483a3dda9a3ae29e54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Mon, 22 Jul 2024 18:51:36 +0300 Subject: [PATCH 11/33] Add `pread` and `pwrite` shims --- src/tools/miri/src/shims/unix/fd.rs | 93 +++++++++++++++---- .../miri/src/shims/unix/foreign_items.rs | 44 ++++++++- src/tools/miri/src/shims/unix/fs.rs | 48 ++++++++++ src/tools/miri/tests/pass/shims/fs.rs | 41 ++++++++ 4 files changed, 205 insertions(+), 21 deletions(-) diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs index 8fb046b5e64cf..de6d27f5290db 100644 --- a/src/tools/miri/src/shims/unix/fd.rs +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -36,6 +36,30 @@ pub trait FileDescription: std::fmt::Debug + Any { throw_unsup_format!("cannot write to {}", self.name()); } + /// Reads as much as possible into the given buffer from a given offset, + /// and returns the number of bytes read. + fn pread<'tcx>( + &mut self, + _communicate_allowed: bool, + _bytes: &mut [u8], + _offset: u64, + _ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("cannot pread from {}", self.name()); + } + + /// Writes as much as possible from the given buffer starting at a given offset, + /// and returns the number of bytes written. + fn pwrite<'tcx>( + &mut self, + _communicate_allowed: bool, + _bytes: &[u8], + _offset: u64, + _ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("cannot pwrite to {}", self.name()); + } + /// Seeks to the given offset (which can be relative to the beginning, end, or current position). /// Returns the new position from the start of the stream. fn seek<'tcx>( @@ -380,7 +404,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok((-1).into()) } - fn read(&mut self, fd: i32, buf: Pointer, count: u64) -> InterpResult<'tcx, i64> { + /// Read data from `fd` into buffer specified by `buf` and `count`. + /// + /// If `offset` is `None`, reads data from current cursor position associated with `fd` + /// and updates cursor position on completion. Otherwise, reads from the specified offset + /// and keeps the cursor unchanged. + fn read( + &mut self, + fd: i32, + buf: Pointer, + count: u64, + offset: Option, + ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); // Isolation check is done via `FileDescriptor` trait. @@ -398,25 +433,31 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let communicate = this.machine.communicate(); // We temporarily dup the FD to be able to retain mutable access to `this`. - let Some(file_descriptor) = this.machine.fds.dup(fd) else { + let Some(fd) = this.machine.fds.dup(fd) else { trace!("read: FD not found"); return this.fd_not_found(); }; - trace!("read: FD mapped to {:?}", file_descriptor); + trace!("read: FD mapped to {fd:?}"); // We want to read at most `count` bytes. We are sure that `count` is not negative // because it was a target's `usize`. Also we are sure that its smaller than // `usize::MAX` because it is bounded by the host's `isize`. let mut bytes = vec![0; usize::try_from(count).unwrap()]; - // `File::read` never returns a value larger than `count`, - // so this cannot fail. - let result = file_descriptor - .borrow_mut() - .read(communicate, &mut bytes, this)? - .map(|c| i64::try_from(c).unwrap()); - drop(file_descriptor); - - match result { + let result = match offset { + None => fd.borrow_mut().read(communicate, &mut bytes, this), + Some(offset) => { + let Ok(offset) = u64::try_from(offset) else { + let einval = this.eval_libc("EINVAL"); + this.set_last_error(einval)?; + return Ok(-1); + }; + fd.borrow_mut().pread(communicate, &mut bytes, offset, this) + } + }; + drop(fd); + + // `File::read` never returns a value larger than `count`, so this cannot fail. + match result?.map(|c| i64::try_from(c).unwrap()) { Ok(read_bytes) => { // If reading to `bytes` did not fail, we write those bytes to the buffer. // Crucially, if fewer than `bytes.len()` bytes were read, only write @@ -434,7 +475,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - fn write(&mut self, fd: i32, buf: Pointer, count: u64) -> InterpResult<'tcx, i64> { + fn write( + &mut self, + fd: i32, + buf: Pointer, + count: u64, + offset: Option, + ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); // Isolation check is done via `FileDescriptor` trait. @@ -451,16 +498,24 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let bytes = this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(count))?.to_owned(); // We temporarily dup the FD to be able to retain mutable access to `this`. - let Some(file_descriptor) = this.machine.fds.dup(fd) else { + let Some(fd) = this.machine.fds.dup(fd) else { return this.fd_not_found(); }; - let result = file_descriptor - .borrow_mut() - .write(communicate, &bytes, this)? - .map(|c| i64::try_from(c).unwrap()); - drop(file_descriptor); + let result = match offset { + None => fd.borrow_mut().write(communicate, &bytes, this), + Some(offset) => { + let Ok(offset) = u64::try_from(offset) else { + let einval = this.eval_libc("EINVAL"); + this.set_last_error(einval)?; + return Ok(-1); + }; + fd.borrow_mut().pwrite(communicate, &bytes, offset, this) + } + }; + drop(fd); + let result = result?.map(|c| i64::try_from(c).unwrap()); this.try_unwrap_io_result(result) } } diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 3a18d62203333..966e590fcc41e 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -92,7 +92,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_pointer(buf)?; let count = this.read_target_usize(count)?; - let result = this.read(fd, buf, count)?; + let result = this.read(fd, buf, count, None)?; this.write_scalar(Scalar::from_target_isize(result, this), dest)?; } "write" => { @@ -101,7 +101,47 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let buf = this.read_pointer(buf)?; let count = this.read_target_usize(n)?; trace!("Called write({:?}, {:?}, {:?})", fd, buf, count); - let result = this.write(fd, buf, count)?; + let result = this.write(fd, buf, count, None)?; + // Now, `result` is the value we return back to the program. + this.write_scalar(Scalar::from_target_isize(result, this), dest)?; + } + "pread" => { + let [fd, buf, count, offset] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let fd = this.read_scalar(fd)?.to_i32()?; + let buf = this.read_pointer(buf)?; + let count = this.read_target_usize(count)?; + let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?; + let result = this.read(fd, buf, count, Some(offset))?; + this.write_scalar(Scalar::from_target_isize(result, this), dest)?; + } + "pwrite" => { + let [fd, buf, n, offset] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let fd = this.read_scalar(fd)?.to_i32()?; + let buf = this.read_pointer(buf)?; + let count = this.read_target_usize(n)?; + let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?; + trace!("Called pwrite({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset); + let result = this.write(fd, buf, count, Some(offset))?; + // Now, `result` is the value we return back to the program. + this.write_scalar(Scalar::from_target_isize(result, this), dest)?; + } + "pread64" => { + let [fd, buf, count, offset] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let fd = this.read_scalar(fd)?.to_i32()?; + let buf = this.read_pointer(buf)?; + let count = this.read_target_usize(count)?; + let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off64_t").size)?; + let result = this.read(fd, buf, count, Some(offset))?; + this.write_scalar(Scalar::from_target_isize(result, this), dest)?; + } + "pwrite64" => { + let [fd, buf, n, offset] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let fd = this.read_scalar(fd)?.to_i32()?; + let buf = this.read_pointer(buf)?; + let count = this.read_target_usize(n)?; + let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off64_t").size)?; + trace!("Called pwrite64({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset); + let result = this.write(fd, buf, count, Some(offset))?; // Now, `result` is the value we return back to the program. this.write_scalar(Scalar::from_target_isize(result, this), dest)?; } diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index e34aa5c09dfe1..80268ced48de7 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -49,6 +49,54 @@ impl FileDescription for FileHandle { Ok(self.file.write(bytes)) } + fn pread<'tcx>( + &mut self, + communicate_allowed: bool, + bytes: &mut [u8], + offset: u64, + _ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx, io::Result> { + assert!(communicate_allowed, "isolation should have prevented even opening a file"); + // Emulates pread using seek + read + seek to restore cursor position. + // Correctness of this emulation relies on sequential nature of Miri execution. + // The closure is used to emulate `try` block, since we "bubble" `io::Error` using `?`. + let mut f = || { + let cursor_pos = self.file.stream_position()?; + self.file.seek(SeekFrom::Start(offset))?; + let res = self.file.read(bytes); + // Attempt to restore cursor position even if the read has failed + self.file + .seek(SeekFrom::Start(cursor_pos)) + .expect("failed to restore file position, this shouldn't be possible"); + res + }; + Ok(f()) + } + + fn pwrite<'tcx>( + &mut self, + communicate_allowed: bool, + bytes: &[u8], + offset: u64, + _ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx, io::Result> { + assert!(communicate_allowed, "isolation should have prevented even opening a file"); + // Emulates pwrite using seek + write + seek to restore cursor position. + // Correctness of this emulation relies on sequential nature of Miri execution. + // The closure is used to emulate `try` block, since we "bubble" `io::Error` using `?`. + let mut f = || { + let cursor_pos = self.file.stream_position()?; + self.file.seek(SeekFrom::Start(offset))?; + let res = self.file.write(bytes); + // Attempt to restore cursor position even if the write has failed + self.file + .seek(SeekFrom::Start(cursor_pos)) + .expect("failed to restore file position, this shouldn't be possible"); + res + }; + Ok(f()) + } + fn seek<'tcx>( &mut self, communicate_allowed: bool, diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs index 16d3e8cab30ab..70e375b098128 100644 --- a/src/tools/miri/tests/pass/shims/fs.rs +++ b/src/tools/miri/tests/pass/shims/fs.rs @@ -30,6 +30,8 @@ fn main() { test_directory(); test_canonicalize(); test_from_raw_os_error(); + #[cfg(unix)] + test_pread_pwrite(); } fn test_path_conversion() { @@ -303,3 +305,42 @@ fn test_from_raw_os_error() { // Make sure we can also format this. let _ = format!("{error:?}"); } + +#[cfg(unix)] +fn test_pread_pwrite() { + use std::os::unix::fs::FileExt; + + let bytes = b"hello world"; + let path = utils::prepare_with_content("miri_test_fs_pread_pwrite.txt", bytes); + let mut f = OpenOptions::new().read(true).write(true).open(path).unwrap(); + + let mut buf1 = [0u8; 3]; + f.seek(SeekFrom::Start(5)).unwrap(); + + // Check that we get expected result after seek + f.read_exact(&mut buf1).unwrap(); + assert_eq!(&buf1, b" wo"); + f.seek(SeekFrom::Start(5)).unwrap(); + + // Check pread + f.read_exact_at(&mut buf1, 2).unwrap(); + assert_eq!(&buf1, b"llo"); + f.read_exact_at(&mut buf1, 6).unwrap(); + assert_eq!(&buf1, b"wor"); + + // Ensure that cursor position is not changed + f.read_exact(&mut buf1).unwrap(); + assert_eq!(&buf1, b" wo"); + f.seek(SeekFrom::Start(5)).unwrap(); + + // Check pwrite + f.write_all_at(b" mo", 6).unwrap(); + + let mut buf2 = [0u8; 11]; + f.read_exact_at(&mut buf2, 0).unwrap(); + assert_eq!(&buf2, b"hello mold"); + + // Ensure that cursor position is not changed + f.read_exact(&mut buf1).unwrap(); + assert_eq!(&buf1, b" m"); +} From c646256f0639002cd9e5872f711f09ec77630a74 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Wed, 24 Jul 2024 05:00:48 +0000 Subject: [PATCH 12/33] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index b09d4f11f68ef..60497630ae0d0 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -9057c3ffec44926d5e149dc13ff3ce1613b69cce +42103d69b73fb4e9d03d5cf66ec12985bb526f6e From a0088d7a813a1f63e5af4d6edc5d2c50a0b3702e Mon Sep 17 00:00:00 2001 From: Konstantinos Andrikopoulos Date: Sat, 20 Jul 2024 11:28:48 +0200 Subject: [PATCH 13/33] Allow getpid in isolation mode, add gettid support In order to support gettid when isolation is enabled and when it is disabled, and satisfy its requirement that: In a single-threaded process, the thread ID is equal to the process ID (PID, as returned by getpid(2)). we define the thread ID to be getpid() + . Since the internal thread id of the main thread is zero, this will satisfy that requirement. However, getpid for now was only supported when isolation was disabled. To support getpid in isolation mode, we return a hardcoded value (1000) and return that instead of the real PID. --- src/tools/miri/src/shims/env.rs | 5 +++++ src/tools/miri/src/shims/unix/env.rs | 17 +++++++++++--- .../src/shims/unix/linux/foreign_items.rs | 5 +++++ src/tools/miri/src/shims/windows/env.rs | 3 +-- src/tools/miri/tests/pass-dep/libc/gettid.rs | 22 +++++++++++++++++++ src/tools/miri/tests/pass/getpid.rs | 15 +++++++++++-- 6 files changed, 60 insertions(+), 7 deletions(-) create mode 100644 src/tools/miri/tests/pass-dep/libc/gettid.rs diff --git a/src/tools/miri/src/shims/env.rs b/src/tools/miri/src/shims/env.rs index 7ad395cccb799..6586ea8e48cff 100644 --- a/src/tools/miri/src/shims/env.rs +++ b/src/tools/miri/src/shims/env.rs @@ -108,4 +108,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { EnvVars::Windows(vars) => vars.get(name), } } + + fn get_pid(&self) -> u32 { + let this = self.eval_context_ref(); + if this.machine.communicate() { std::process::id() } else { 1000 } + } } diff --git a/src/tools/miri/src/shims/unix/env.rs b/src/tools/miri/src/shims/unix/env.rs index 405431f4327db..3b8ad65195b8a 100644 --- a/src/tools/miri/src/shims/unix/env.rs +++ b/src/tools/miri/src/shims/unix/env.rs @@ -274,12 +274,23 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); this.assert_target_os_is_unix("getpid"); - this.check_no_isolation("`getpid`")?; - // The reason we need to do this wacky of a conversion is because // `libc::getpid` returns an i32, however, `std::process::id()` return an u32. // So we un-do the conversion that stdlib does and turn it back into an i32. #[allow(clippy::cast_possible_wrap)] - Ok(std::process::id() as i32) + Ok(this.get_pid() as i32) + } + + fn linux_gettid(&mut self) -> InterpResult<'tcx, i32> { + let this = self.eval_context_ref(); + this.assert_target_os("linux", "gettid"); + + let index = this.machine.threads.active_thread().to_u32(); + + // Compute a TID for this thread, ensuring that the main thread has PID == TID. + let tid = this.get_pid().strict_add(index); + + #[allow(clippy::cast_possible_wrap)] + Ok(tid as i32) } } diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs index 95bee38cd7835..20c6a23479421 100644 --- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs @@ -94,6 +94,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { )?; this.write_scalar(res, dest)?; } + "gettid" => { + let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let result = this.linux_gettid()?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } // Dynamically invoked syscalls "syscall" => { diff --git a/src/tools/miri/src/shims/windows/env.rs b/src/tools/miri/src/shims/windows/env.rs index ed3eb69798637..77ae06bd5c2d8 100644 --- a/src/tools/miri/src/shims/windows/env.rs +++ b/src/tools/miri/src/shims/windows/env.rs @@ -200,9 +200,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn GetCurrentProcessId(&mut self) -> InterpResult<'tcx, u32> { let this = self.eval_context_mut(); this.assert_target_os("windows", "GetCurrentProcessId"); - this.check_no_isolation("`GetCurrentProcessId`")?; - Ok(std::process::id()) + Ok(this.get_pid()) } #[allow(non_snake_case)] diff --git a/src/tools/miri/tests/pass-dep/libc/gettid.rs b/src/tools/miri/tests/pass-dep/libc/gettid.rs new file mode 100644 index 0000000000000..87405b02ac35d --- /dev/null +++ b/src/tools/miri/tests/pass-dep/libc/gettid.rs @@ -0,0 +1,22 @@ +//@only-target-linux +//@revisions: with_isolation without_isolation +//@[without_isolation] compile-flags: -Zmiri-disable-isolation + +use libc::{getpid, gettid}; +use std::thread; + +fn main() { + thread::spawn(|| { + // Test that in isolation mode a deterministic value will be returned. + // The value 1001 is not important, we only care that whatever the value + // is, won't change from execution to execution. + #[cfg(with_isolation)] + assert_eq!(unsafe { gettid() }, 1001); + + assert_ne!(unsafe { gettid() }, unsafe { getpid() }); + }); + + // Test that the thread ID of the main thread is the same as the process + // ID. + assert_eq!(unsafe { gettid() }, unsafe { getpid() }); +} diff --git a/src/tools/miri/tests/pass/getpid.rs b/src/tools/miri/tests/pass/getpid.rs index 733545462ebc0..f350fafff4a26 100644 --- a/src/tools/miri/tests/pass/getpid.rs +++ b/src/tools/miri/tests/pass/getpid.rs @@ -1,9 +1,20 @@ -//@compile-flags: -Zmiri-disable-isolation +//@revisions: with_isolation without_isolation +//@[without_isolation] compile-flags: -Zmiri-disable-isolation fn getpid() -> u32 { std::process::id() } fn main() { - getpid(); + let pid = getpid(); + + std::thread::spawn(move || { + assert_eq!(getpid(), pid); + }); + + // Test that in isolation mode a deterministic value will be returned. + // The value 1000 is not important, we only care that whatever the value + // is, won't change from execution to execution. + #[cfg(with_isolation)] + assert_eq!(pid, 1000); } From c45f4646393b4ecab0c75b251f409bf12a1999da Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 22 Jun 2024 16:45:20 +0200 Subject: [PATCH 14/33] show warning when Stacked Borrows skips a reborrow due to 'extern type' --- .../src/borrow_tracker/stacked_borrows/mod.rs | 15 ++++++++- src/tools/miri/src/diagnostics.rs | 31 ++++++++++++++++--- .../fail/extern-type-field-offset.stderr | 13 +++++++- .../ptr_metadata_uninit_slice_len.stderr | 10 +++--- src/tools/miri/tests/pass/box.stack.stderr | 10 +++--- .../miri/tests/pass/extern_types.stack.stderr | 21 ++++++++++--- .../stacked-borrows/issue-miri-2389.stderr | 10 +++--- 7 files changed, 83 insertions(+), 27 deletions(-) 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 603733f9dc000..1d75486a78189 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -5,6 +5,7 @@ pub mod diagnostics; mod item; mod stack; +use std::cell::RefCell; use std::cmp; use std::fmt::Write; use std::mem; @@ -820,7 +821,19 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> { // See https://github.com/rust-lang/unsafe-code-guidelines/issues/276. let size = match size { Some(size) => size, - None => return Ok(place.clone()), + None => { + // The first time this happens, show a warning. + thread_local! { static WARNING_SHOWN: RefCell = const { RefCell::new(false) }; } + WARNING_SHOWN.with_borrow_mut(|shown| { + if *shown { + return; + } + // Not yet shown. Show it! + *shown = true; + this.emit_diagnostic(NonHaltingDiagnostic::ExternTypeReborrow); + }); + return Ok(place.clone()); + } }; // Compute new borrow. diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 647d7d44bb1bb..45a8a54bc298a 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -130,6 +130,7 @@ pub enum NonHaltingDiagnostic { WeakMemoryOutdatedLoad { ptr: Pointer, }, + ExternTypeReborrow, } /// Level of Miri specific diagnostics @@ -593,6 +594,8 @@ impl<'tcx> MiriMachine<'tcx> { RejectedIsolatedOp(_) => ("operation rejected by isolation".to_string(), DiagLevel::Warning), Int2Ptr { .. } => ("integer-to-pointer cast".to_string(), DiagLevel::Warning), + ExternTypeReborrow => + ("reborrow of reference to `extern type`".to_string(), DiagLevel::Warning), CreatedPointerTag(..) | PoppedPointerTag(..) | CreatedCallId(..) @@ -630,6 +633,8 @@ impl<'tcx> MiriMachine<'tcx> { Int2Ptr { .. } => format!("integer-to-pointer cast"), WeakMemoryOutdatedLoad { ptr } => format!("weak memory emulation: outdated value returned from load at {ptr}"), + ExternTypeReborrow => + format!("reborrow of a reference to `extern type` is not properly supported"), }; let notes = match &e { @@ -647,34 +652,50 @@ impl<'tcx> MiriMachine<'tcx> { ( None, format!( - "This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, which means that Miri might miss pointer bugs in this program." + "this program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, which means that Miri might miss pointer bugs in this program" ), ), ( None, format!( - "See https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation." + "see https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation" ), ), ( None, format!( - "To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead." + "to ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead" ), ), ( None, format!( - "You can then set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics." + "you can then set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics" ), ), ( None, format!( - "Alternatively, `MIRIFLAGS=-Zmiri-permissive-provenance` disables this warning." + "alternatively, `MIRIFLAGS=-Zmiri-permissive-provenance` disables this warning" ), ), ], + ExternTypeReborrow => { + vec![ + ( + None, + format!( + "`extern type` are not compatible with the Stacked Borrows aliasing model implemented by Miri; Miri may miss bugs in this code" + ), + ), + ( + None, + format!( + "try running with `MIRIFLAGS=-Zmiri-tree-borrows` to use the more permissive but also even more experimental Tree Borrows aliasing checks instead" + ), + ), + ] + } _ => vec![], }; diff --git a/src/tools/miri/tests/fail/extern-type-field-offset.stderr b/src/tools/miri/tests/fail/extern-type-field-offset.stderr index 3ed5732b4eb06..c07b63e0c0384 100644 --- a/src/tools/miri/tests/fail/extern-type-field-offset.stderr +++ b/src/tools/miri/tests/fail/extern-type-field-offset.stderr @@ -1,3 +1,14 @@ +warning: reborrow of reference to `extern type` + --> $DIR/extern-type-field-offset.rs:LL:CC + | +LL | let x: &Newtype = unsafe { &*(&buf as *const _ as *const Newtype) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reborrow of a reference to `extern type` is not properly supported + | + = help: `extern type` are not compatible with the Stacked Borrows aliasing model implemented by Miri; Miri may miss bugs in this code + = help: try running with `MIRIFLAGS=-Zmiri-tree-borrows` to use the more permissive but also even more experimental Tree Borrows aliasing checks instead + = note: BACKTRACE: + = note: inside `main` at $DIR/extern-type-field-offset.rs:LL:CC + error: unsupported operation: `extern type` field does not have a known offset --> $DIR/extern-type-field-offset.rs:LL:CC | @@ -10,5 +21,5 @@ LL | let _field = &x.a; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to 1 previous error +error: aborting due to 1 previous error; 1 warning emitted diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr index 217bc82010df9..84023cf793713 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr @@ -4,11 +4,11 @@ warning: integer-to-pointer cast LL | (*p.as_mut_ptr().cast::<[*const i32; 2]>())[0] = 4 as *const i32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast | - = help: This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, which means that Miri might miss pointer bugs in this program. - = help: See https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation. - = help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead. - = help: You can then set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics. - = help: Alternatively, `MIRIFLAGS=-Zmiri-permissive-provenance` disables this warning. + = help: this program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead + = help: you can then set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics + = help: alternatively, `MIRIFLAGS=-Zmiri-permissive-provenance` disables this warning = note: BACKTRACE: = note: inside `main` at $DIR/ptr_metadata_uninit_slice_len.rs:LL:CC diff --git a/src/tools/miri/tests/pass/box.stack.stderr b/src/tools/miri/tests/pass/box.stack.stderr index 341f84c8992df..f2d01b518fc80 100644 --- a/src/tools/miri/tests/pass/box.stack.stderr +++ b/src/tools/miri/tests/pass/box.stack.stderr @@ -4,11 +4,11 @@ warning: integer-to-pointer cast LL | let r2 = ((r as usize) + 0) as *mut i32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast | - = help: This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, which means that Miri might miss pointer bugs in this program. - = help: See https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation. - = help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead. - = help: You can then set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics. - = help: Alternatively, `MIRIFLAGS=-Zmiri-permissive-provenance` disables this warning. + = help: this program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead + = help: you can then set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics + = help: alternatively, `MIRIFLAGS=-Zmiri-permissive-provenance` disables this warning = note: BACKTRACE: = note: inside `into_raw` at $DIR/box.rs:LL:CC note: inside `main` diff --git a/src/tools/miri/tests/pass/extern_types.stack.stderr b/src/tools/miri/tests/pass/extern_types.stack.stderr index 03a9167abbc7c..9b6f632eb5a22 100644 --- a/src/tools/miri/tests/pass/extern_types.stack.stderr +++ b/src/tools/miri/tests/pass/extern_types.stack.stderr @@ -4,11 +4,22 @@ warning: integer-to-pointer cast LL | let x: &Foo = unsafe { &*(16 as *const Foo) }; | ^^^^^^^^^^^^^^^^^^ integer-to-pointer cast | - = help: This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, which means that Miri might miss pointer bugs in this program. - = help: See https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation. - = help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead. - = help: You can then set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics. - = help: Alternatively, `MIRIFLAGS=-Zmiri-permissive-provenance` disables this warning. + = help: this program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead + = help: you can then set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics + = help: alternatively, `MIRIFLAGS=-Zmiri-permissive-provenance` disables this warning + = note: BACKTRACE: + = note: inside `main` at $DIR/extern_types.rs:LL:CC + +warning: reborrow of reference to `extern type` + --> $DIR/extern_types.rs:LL:CC + | +LL | let x: &Foo = unsafe { &*(16 as *const Foo) }; + | ^^^^^^^^^^^^^^^^^^^^ reborrow of a reference to `extern type` is not properly supported + | + = help: `extern type` are not compatible with the Stacked Borrows aliasing model implemented by Miri; Miri may miss bugs in this code + = help: try running with `MIRIFLAGS=-Zmiri-tree-borrows` to use the more permissive but also even more experimental Tree Borrows aliasing checks instead = note: BACKTRACE: = note: inside `main` at $DIR/extern_types.rs:LL:CC diff --git a/src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.stderr b/src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.stderr index b0e1adf27d183..216bb6c76bc9a 100644 --- a/src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.stderr +++ b/src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.stderr @@ -4,11 +4,11 @@ warning: integer-to-pointer cast LL | let wildcard = &root0 as *const Cell as usize as *const Cell; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast | - = help: This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, which means that Miri might miss pointer bugs in this program. - = help: See https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation. - = help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead. - = help: You can then set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics. - = help: Alternatively, `MIRIFLAGS=-Zmiri-permissive-provenance` disables this warning. + = help: this program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead + = help: you can then set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics + = help: alternatively, `MIRIFLAGS=-Zmiri-permissive-provenance` disables this warning = note: BACKTRACE: = note: inside `main` at $DIR/issue-miri-2389.rs:LL:CC From 6da04f95a7233089cf714d24a160a5dbaa8d84b9 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Thu, 25 Jul 2024 05:10:15 +0000 Subject: [PATCH 15/33] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 60497630ae0d0..9868188eeee70 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -42103d69b73fb4e9d03d5cf66ec12985bb526f6e +e7d66eac5e8e8f60370c98d186aee9fa0ebd7845 From b5490357bac87ac70ca6f4729bd7fd127529eff5 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Fri, 26 Jul 2024 05:00:25 +0000 Subject: [PATCH 16/33] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 9868188eeee70..e1a6084b22eda 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -e7d66eac5e8e8f60370c98d186aee9fa0ebd7845 +72d73cec61aa8f85901358cd5d386d5dd066fe52 From 7bc7e6789ac0cd4bab726f3d18c8e1201674f1fc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 26 Jul 2024 08:53:38 +0200 Subject: [PATCH 17/33] better diagnostics for Tree Borrows + int2ptr casts --- src/tools/miri/src/bin/miri.rs | 8 ++ src/tools/miri/src/borrow_tracker/mod.rs | 4 + src/tools/miri/src/diagnostics.rs | 23 +++-- src/tools/miri/tests/pass/adjacent-allocs.rs | 2 - src/tools/miri/tests/pass/box.rs | 3 +- src/tools/miri/tests/pass/box.stack.stderr | 33 ------- .../pass/{box.stack.stdout => box.stdout} | 0 src/tools/miri/tests/pass/box.tree.stdout | 3 - src/tools/miri/tests/pass/extern_types.rs | 8 +- .../miri/tests/pass/extern_types.stack.stderr | 18 +--- src/tools/miri/tests/pass/intptrcast.rs | 2 - src/tools/miri/tests/pass/pointers.rs | 2 - src/tools/miri/tests/pass/ptr_int_casts.rs | 3 +- .../miri/tests/pass/ptr_int_casts.tree.stderr | 89 +++++++++++++++++++ .../miri/tests/pass/ptr_int_from_exposed.rs | 3 +- .../pass/ptr_int_from_exposed.tree.stderr | 19 ++++ 16 files changed, 150 insertions(+), 70 deletions(-) delete mode 100644 src/tools/miri/tests/pass/box.stack.stderr rename src/tools/miri/tests/pass/{box.stack.stdout => box.stdout} (100%) delete mode 100644 src/tools/miri/tests/pass/box.tree.stdout create mode 100644 src/tools/miri/tests/pass/ptr_int_casts.tree.stderr create mode 100644 src/tools/miri/tests/pass/ptr_int_from_exposed.tree.stderr diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 9f3fa075f38f6..25b154a8206c9 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -620,6 +620,14 @@ fn main() { "-Zmiri-unique-is-unique only has an effect when -Zmiri-tree-borrows is also used" ); } + // Tree Borrows + permissive provenance does not work. + if miri_config.provenance_mode == ProvenanceMode::Permissive + && matches!(miri_config.borrow_tracker, Some(BorrowTrackerMethod::TreeBorrows)) + { + show_error!( + "Tree Borrows does not support integer-to-pointer casts, and is hence not compatible with permissive provenance" + ); + } debug!("rustc arguments: {:?}", rustc_args); debug!("crate arguments: {:?}", miri_config.args); diff --git a/src/tools/miri/src/borrow_tracker/mod.rs b/src/tools/miri/src/borrow_tracker/mod.rs index c9e7e300593bc..d537a7fbc1798 100644 --- a/src/tools/miri/src/borrow_tracker/mod.rs +++ b/src/tools/miri/src/borrow_tracker/mod.rs @@ -232,6 +232,10 @@ impl GlobalStateInner { pub fn remove_unreachable_allocs(&mut self, allocs: &LiveAllocs<'_, '_>) { self.root_ptr_tags.retain(|id, _| allocs.is_live(*id)); } + + pub fn borrow_tracker_method(&self) -> BorrowTrackerMethod { + self.borrow_tracker_method + } } /// Which borrow tracking method to use diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 45a8a54bc298a..6d10a21293b65 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -647,8 +647,8 @@ impl<'tcx> MiriMachine<'tcx> { }; let helps = match &e { - Int2Ptr { details: true } => - vec![ + Int2Ptr { details: true } => { + let mut v = vec![ ( None, format!( @@ -673,13 +673,26 @@ impl<'tcx> MiriMachine<'tcx> { "you can then set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics" ), ), - ( + ]; + if self.borrow_tracker.as_ref().is_some_and(|b| { + matches!(b.borrow().borrow_tracker_method(), BorrowTrackerMethod::TreeBorrows) + }) { + v.push(( + None, + format!( + "Tree Borrows does not support integer-to-pointer casts, so the program is likely to go wrong when this pointer gets used" + ), + )); + } else { + v.push(( None, format!( "alternatively, `MIRIFLAGS=-Zmiri-permissive-provenance` disables this warning" ), - ), - ], + )); + } + v + } ExternTypeReborrow => { vec![ ( diff --git a/src/tools/miri/tests/pass/adjacent-allocs.rs b/src/tools/miri/tests/pass/adjacent-allocs.rs index 8be4bdac7e1bb..711c54fd68ad5 100644 --- a/src/tools/miri/tests/pass/adjacent-allocs.rs +++ b/src/tools/miri/tests/pass/adjacent-allocs.rs @@ -1,5 +1,3 @@ -//@revisions: stack tree -//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-permissive-provenance fn ensure_allocs_can_be_adjacent() { diff --git a/src/tools/miri/tests/pass/box.rs b/src/tools/miri/tests/pass/box.rs index 174bf8be30b22..693209c04568f 100644 --- a/src/tools/miri/tests/pass/box.rs +++ b/src/tools/miri/tests/pass/box.rs @@ -1,5 +1,4 @@ -//@revisions: stack tree -//@[tree]compile-flags: -Zmiri-tree-borrows -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance #![feature(ptr_internals)] fn main() { diff --git a/src/tools/miri/tests/pass/box.stack.stderr b/src/tools/miri/tests/pass/box.stack.stderr deleted file mode 100644 index f2d01b518fc80..0000000000000 --- a/src/tools/miri/tests/pass/box.stack.stderr +++ /dev/null @@ -1,33 +0,0 @@ -warning: integer-to-pointer cast - --> $DIR/box.rs:LL:CC - | -LL | let r2 = ((r as usize) + 0) as *mut i32; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast - | - = help: this program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead - = help: you can then set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics - = help: alternatively, `MIRIFLAGS=-Zmiri-permissive-provenance` disables this warning - = note: BACKTRACE: - = note: inside `into_raw` at $DIR/box.rs:LL:CC -note: inside `main` - --> $DIR/box.rs:LL:CC - | -LL | into_raw(); - | ^^^^^^^^^^ - -warning: integer-to-pointer cast - --> $DIR/box.rs:LL:CC - | -LL | let r = ((u.as_ptr() as usize) + 0) as *mut i32; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast - | - = note: BACKTRACE: - = note: inside `into_unique` at $DIR/box.rs:LL:CC -note: inside `main` - --> $DIR/box.rs:LL:CC - | -LL | into_unique(); - | ^^^^^^^^^^^^^ - diff --git a/src/tools/miri/tests/pass/box.stack.stdout b/src/tools/miri/tests/pass/box.stdout similarity index 100% rename from src/tools/miri/tests/pass/box.stack.stdout rename to src/tools/miri/tests/pass/box.stdout diff --git a/src/tools/miri/tests/pass/box.tree.stdout b/src/tools/miri/tests/pass/box.tree.stdout deleted file mode 100644 index 230ef368da644..0000000000000 --- a/src/tools/miri/tests/pass/box.tree.stdout +++ /dev/null @@ -1,3 +0,0 @@ -pair_foo = PairFoo { fst: Foo(42), snd: Foo(1337) } -foo #0 = Foo(42) -foo #1 = Foo(1337) diff --git a/src/tools/miri/tests/pass/extern_types.rs b/src/tools/miri/tests/pass/extern_types.rs index 7ac93577f0cd5..eade5c6ac0874 100644 --- a/src/tools/miri/tests/pass/extern_types.rs +++ b/src/tools/miri/tests/pass/extern_types.rs @@ -1,12 +1,14 @@ //@revisions: stack tree -//@[tree]compile-flags: -Zmiri-tree-borrows -Zmiri-permissive-provenance -#![feature(extern_types)] +//@[tree]compile-flags: -Zmiri-tree-borrows +#![feature(extern_types, strict_provenance)] + +use std::ptr; extern "C" { type Foo; } fn main() { - let x: &Foo = unsafe { &*(16 as *const Foo) }; + let x: &Foo = unsafe { &*(ptr::without_provenance::<()>(16) as *const Foo) }; let _y: &Foo = &*x; } diff --git a/src/tools/miri/tests/pass/extern_types.stack.stderr b/src/tools/miri/tests/pass/extern_types.stack.stderr index 9b6f632eb5a22..2c9fc0192af83 100644 --- a/src/tools/miri/tests/pass/extern_types.stack.stderr +++ b/src/tools/miri/tests/pass/extern_types.stack.stderr @@ -1,22 +1,8 @@ -warning: integer-to-pointer cast - --> $DIR/extern_types.rs:LL:CC - | -LL | let x: &Foo = unsafe { &*(16 as *const Foo) }; - | ^^^^^^^^^^^^^^^^^^ integer-to-pointer cast - | - = help: this program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead - = help: you can then set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics - = help: alternatively, `MIRIFLAGS=-Zmiri-permissive-provenance` disables this warning - = note: BACKTRACE: - = note: inside `main` at $DIR/extern_types.rs:LL:CC - warning: reborrow of reference to `extern type` --> $DIR/extern_types.rs:LL:CC | -LL | let x: &Foo = unsafe { &*(16 as *const Foo) }; - | ^^^^^^^^^^^^^^^^^^^^ reborrow of a reference to `extern type` is not properly supported +LL | let x: &Foo = unsafe { &*(ptr::without_provenance::<()>(16) as *const Foo) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reborrow of a reference to `extern type` is not properly supported | = help: `extern type` are not compatible with the Stacked Borrows aliasing model implemented by Miri; Miri may miss bugs in this code = help: try running with `MIRIFLAGS=-Zmiri-tree-borrows` to use the more permissive but also even more experimental Tree Borrows aliasing checks instead diff --git a/src/tools/miri/tests/pass/intptrcast.rs b/src/tools/miri/tests/pass/intptrcast.rs index fb1a1dfae5d14..a304f2751bdb6 100644 --- a/src/tools/miri/tests/pass/intptrcast.rs +++ b/src/tools/miri/tests/pass/intptrcast.rs @@ -1,5 +1,3 @@ -//@revisions: stack tree -//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-permissive-provenance use std::mem; diff --git a/src/tools/miri/tests/pass/pointers.rs b/src/tools/miri/tests/pass/pointers.rs index c7b720dafa20b..280a815abc430 100644 --- a/src/tools/miri/tests/pass/pointers.rs +++ b/src/tools/miri/tests/pass/pointers.rs @@ -1,5 +1,3 @@ -//@revisions: stack tree -//@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-permissive-provenance #![feature(ptr_metadata, const_raw_ptr_comparison)] #![allow(ambiguous_wide_pointer_comparisons)] diff --git a/src/tools/miri/tests/pass/ptr_int_casts.rs b/src/tools/miri/tests/pass/ptr_int_casts.rs index a2fcd098107a6..684e8f6ec7bdd 100644 --- a/src/tools/miri/tests/pass/ptr_int_casts.rs +++ b/src/tools/miri/tests/pass/ptr_int_casts.rs @@ -1,6 +1,7 @@ //@revisions: stack tree +// Tree Borrows doesn't support int2ptr casts, but let's make sure we don't immediately crash either. //@[tree]compile-flags: -Zmiri-tree-borrows -//@compile-flags: -Zmiri-permissive-provenance +//@[stack]compile-flags: -Zmiri-permissive-provenance use std::mem; use std::ptr; diff --git a/src/tools/miri/tests/pass/ptr_int_casts.tree.stderr b/src/tools/miri/tests/pass/ptr_int_casts.tree.stderr new file mode 100644 index 0000000000000..a34474ee0d627 --- /dev/null +++ b/src/tools/miri/tests/pass/ptr_int_casts.tree.stderr @@ -0,0 +1,89 @@ +warning: integer-to-pointer cast + --> $DIR/ptr_int_casts.rs:LL:CC + | +LL | assert_eq!(1 as *const i32 as usize, 1); + | ^^^^^^^^^^^^^^^ integer-to-pointer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead + = help: you can then set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics + = help: Tree Borrows does not support integer-to-pointer casts, so the program is likely to go wrong when this pointer gets used + = note: BACKTRACE: + = note: inside `ptr_int_casts` at $DIR/ptr_int_casts.rs:LL:CC +note: inside `main` + --> $DIR/ptr_int_casts.rs:LL:CC + | +LL | ptr_int_casts(); + | ^^^^^^^^^^^^^^^ + +warning: integer-to-pointer cast + --> $DIR/ptr_int_casts.rs:LL:CC + | +LL | assert_eq!((1 as *const i32).wrapping_offset(4) as usize, 1 + 4 * 4); + | ^^^^^^^^^^^^^^^^^ integer-to-pointer cast + | + = note: BACKTRACE: + = note: inside `ptr_int_casts` at $DIR/ptr_int_casts.rs:LL:CC +note: inside `main` + --> $DIR/ptr_int_casts.rs:LL:CC + | +LL | ptr_int_casts(); + | ^^^^^^^^^^^^^^^ + +warning: integer-to-pointer cast + --> $DIR/ptr_int_casts.rs:LL:CC + | +LL | *val = (1 as *const u8).wrapping_offset(-4); + | ^^^^^^^^^^^^^^^^ integer-to-pointer cast + | + = note: BACKTRACE: + = note: inside `ptr_int_casts` at $DIR/ptr_int_casts.rs:LL:CC +note: inside `main` + --> $DIR/ptr_int_casts.rs:LL:CC + | +LL | ptr_int_casts(); + | ^^^^^^^^^^^^^^^ + +warning: integer-to-pointer cast + --> $DIR/ptr_int_casts.rs:LL:CC + | +LL | let y = y as *const _; + | ^^^^^^^^^^^^^ integer-to-pointer cast + | + = note: BACKTRACE: + = note: inside `ptr_int_casts` at $DIR/ptr_int_casts.rs:LL:CC +note: inside `main` + --> $DIR/ptr_int_casts.rs:LL:CC + | +LL | ptr_int_casts(); + | ^^^^^^^^^^^^^^^ + +warning: integer-to-pointer cast + --> $DIR/ptr_int_casts.rs:LL:CC + | +LL | let x: fn() -> i32 = unsafe { mem::transmute(y as *mut u8) }; + | ^^^^^^^^^^^^ integer-to-pointer cast + | + = note: BACKTRACE: + = note: inside `ptr_int_casts` at $DIR/ptr_int_casts.rs:LL:CC +note: inside `main` + --> $DIR/ptr_int_casts.rs:LL:CC + | +LL | ptr_int_casts(); + | ^^^^^^^^^^^^^^^ + +warning: integer-to-pointer cast + --> $DIR/ptr_int_casts.rs:LL:CC + | +LL | assert_eq!((-1i32) as usize as *const i32 as usize, (-1i32) as usize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast + | + = note: BACKTRACE: + = note: inside `ptr_int_casts` at $DIR/ptr_int_casts.rs:LL:CC +note: inside `main` + --> $DIR/ptr_int_casts.rs:LL:CC + | +LL | ptr_int_casts(); + | ^^^^^^^^^^^^^^^ + diff --git a/src/tools/miri/tests/pass/ptr_int_from_exposed.rs b/src/tools/miri/tests/pass/ptr_int_from_exposed.rs index 5690d7865bbc3..f6ebf0632a179 100644 --- a/src/tools/miri/tests/pass/ptr_int_from_exposed.rs +++ b/src/tools/miri/tests/pass/ptr_int_from_exposed.rs @@ -1,6 +1,7 @@ //@revisions: stack tree +// Tree Borrows doesn't support int2ptr casts, but let's make sure we don't immediately crash either. //@[tree]compile-flags: -Zmiri-tree-borrows -//@compile-flags: -Zmiri-permissive-provenance +//@[stack]compile-flags: -Zmiri-permissive-provenance #![feature(strict_provenance, exposed_provenance)] use std::ptr; diff --git a/src/tools/miri/tests/pass/ptr_int_from_exposed.tree.stderr b/src/tools/miri/tests/pass/ptr_int_from_exposed.tree.stderr new file mode 100644 index 0000000000000..614b0d26a6304 --- /dev/null +++ b/src/tools/miri/tests/pass/ptr_int_from_exposed.tree.stderr @@ -0,0 +1,19 @@ +warning: integer-to-pointer cast + --> $DIR/ptr_int_from_exposed.rs:LL:CC + | +LL | let ptr = ptr::with_exposed_provenance::(x_usize).wrapping_offset(-128); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead + = help: you can then set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics + = help: Tree Borrows does not support integer-to-pointer casts, so the program is likely to go wrong when this pointer gets used + = note: BACKTRACE: + = note: inside `ptr_roundtrip_out_of_bounds` at $DIR/ptr_int_from_exposed.rs:LL:CC +note: inside `main` + --> $DIR/ptr_int_from_exposed.rs:LL:CC + | +LL | ptr_roundtrip_out_of_bounds(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + From 5e1f8e2d07d2a32a1f234cf80efcb703aa87a989 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 26 Jul 2024 09:06:58 +0200 Subject: [PATCH 18/33] diagnostics: add a macro to make things a bit easier to read --- src/tools/miri/src/diagnostics.rs | 135 +++++++++++++----------------- 1 file changed, 59 insertions(+), 76 deletions(-) diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 6d10a21293b65..1bed55743d4af 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -140,6 +140,15 @@ pub enum DiagLevel { Note, } +/// Generate a note/help text without a span. +macro_rules! note { + ($($tt:tt)*) => { (None, format!($($tt)*)) }; +} +/// Generate a note/help text with a span. +macro_rules! note_span { + ($span:expr, $($tt:tt)*) => { (Some($span), format!($($tt)*)) }; +} + /// Attempts to prune a stacktrace to omit the Rust runtime, and returns a bool indicating if any /// frames were pruned. If the stacktrace does not have any local frames, we conclude that it must /// be pointing to a problem in the Rust runtime itself, and do not prune it at all. @@ -228,38 +237,38 @@ pub fn report_error<'tcx>( let helps = match info { UnsupportedInIsolation(_) => vec![ - (None, format!("set `MIRIFLAGS=-Zmiri-disable-isolation` to disable isolation;")), - (None, format!("or set `MIRIFLAGS=-Zmiri-isolation-error=warn` to make Miri return an error code from isolated operations (if supported for that operation) and continue with a warning")), + note!("set `MIRIFLAGS=-Zmiri-disable-isolation` to disable isolation;"), + note!("or set `MIRIFLAGS=-Zmiri-isolation-error=warn` to make Miri return an error code from isolated operations (if supported for that operation) and continue with a warning"), ], UnsupportedForeignItem(_) => { vec![ - (None, format!("if this is a basic API commonly used on this target, please report an issue with Miri")), - (None, format!("however, note that Miri does not aim to support every FFI function out there; for instance, we will not support APIs for things such as GUIs, scripting languages, or databases")), + note!("if this is a basic API commonly used on this target, please report an issue with Miri"), + note!("however, note that Miri does not aim to support every FFI function out there; for instance, we will not support APIs for things such as GUIs, scripting languages, or databases"), ] } StackedBorrowsUb { help, history, .. } => { msg.extend(help.clone()); let mut helps = vec![ - (None, format!("this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental")), - (None, format!("see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information")), + note!("this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental"), + note!("see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information"), ]; if let Some(TagHistory {created, invalidated, protected}) = history.clone() { helps.push((Some(created.1), created.0)); if let Some((msg, span)) = invalidated { - helps.push((Some(span), msg)); + helps.push(note_span!(span, "{msg}")); } if let Some((protector_msg, protector_span)) = protected { - helps.push((Some(protector_span), protector_msg)); + helps.push(note_span!(protector_span, "{protector_msg}")); } } helps }, TreeBorrowsUb { title: _, details, history } => { let mut helps = vec![ - (None, format!("this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental")) + note!("this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental") ]; for m in details { - helps.push((None, m.clone())); + helps.push(note!("{m}")); } for event in history.events.clone() { helps.push(event); @@ -268,26 +277,26 @@ pub fn report_error<'tcx>( } MultipleSymbolDefinitions { first, first_crate, second, second_crate, .. } => vec![ - (Some(*first), format!("it's first defined here, in crate `{first_crate}`")), - (Some(*second), format!("then it's defined here again, in crate `{second_crate}`")), + note_span!(*first, "it's first defined here, in crate `{first_crate}`"), + note_span!(*second, "then it's defined here again, in crate `{second_crate}`"), ], SymbolShimClashing { link_name, span } => - vec![(Some(*span), format!("the `{link_name}` symbol is defined here"))], + vec![note_span!(*span, "the `{link_name}` symbol is defined here")], Int2PtrWithStrictProvenance => - vec![(None, format!("use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead"))], + vec![note!("use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead")], DataRace { op1, extra, retag_explain, .. } => { - let mut helps = vec![(Some(op1.span), format!("and (1) occurred earlier here"))]; + let mut helps = vec![note_span!(op1.span, "and (1) occurred earlier here")]; if let Some(extra) = extra { - helps.push((None, format!("{extra}"))); - helps.push((None, format!("see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model"))); + helps.push(note!("{extra}")); + helps.push(note!("see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model")); } if *retag_explain { - helps.push((None, "retags occur on all (re)borrows and as well as when references are copied or moved".to_owned())); - helps.push((None, "retags permit optimizations that insert speculative reads or writes".to_owned())); - helps.push((None, "therefore from the perspective of data races, a retag has the same implications as a read or write".to_owned())); + helps.push(note!("retags occur on all (re)borrows and as well as when references are copied or moved")); + helps.push(note!("retags permit optimizations that insert speculative reads or writes")); + helps.push(note!("therefore from the perspective of data races, a retag has the same implications as a read or write")); } - helps.push((None, format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior"))); - helps.push((None, format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information"))); + helps.push(note!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior")); + helps.push(note!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information")); helps } , @@ -332,32 +341,32 @@ pub fn report_error<'tcx>( let helps = match e.kind() { Unsupported(_) => vec![ - (None, format!("this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support")), + note!("this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support"), ], UndefinedBehavior(AlignmentCheckFailed { .. }) if ecx.machine.check_alignment == AlignmentCheck::Symbolic => vec![ - (None, format!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior")), - (None, format!("but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives")), + note!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior"), + note!("but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives"), ], UndefinedBehavior(info) => { let mut helps = vec![ - (None, format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior")), - (None, format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information")), + note!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior"), + note!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information"), ]; match info { PointerUseAfterFree(alloc_id, _) | PointerOutOfBounds { alloc_id, .. } => { if let Some(span) = ecx.machine.allocated_span(*alloc_id) { - helps.push((Some(span), format!("{:?} was allocated here:", alloc_id))); + helps.push(note_span!(span, "{:?} was allocated here:", alloc_id)); } if let Some(span) = ecx.machine.deallocated_span(*alloc_id) { - helps.push((Some(span), format!("{:?} was deallocated here:", alloc_id))); + helps.push(note_span!(span, "{:?} was deallocated here:", alloc_id)); } } AbiMismatchArgument { .. } | AbiMismatchReturn { .. } => { - helps.push((None, format!("this means these two types are not *guaranteed* to be ABI-compatible across all targets"))); - helps.push((None, format!("if you think this code should be accepted anyway, please report an issue with Miri"))); + helps.push(note!("this means these two types are not *guaranteed* to be ABI-compatible across all targets")); + helps.push(note!("if you think this code should be accepted anyway, please report an issue with Miri")); } _ => {}, } @@ -639,9 +648,7 @@ impl<'tcx> MiriMachine<'tcx> { let notes = match &e { ProgressReport { block_count } => { - // It is important that each progress report is slightly different, since - // identical diagnostics are being deduplicated. - vec![(None, format!("so far, {block_count} basic blocks have been executed"))] + vec![note!("so far, {block_count} basic blocks have been executed")] } _ => vec![], }; @@ -649,63 +656,39 @@ impl<'tcx> MiriMachine<'tcx> { let helps = match &e { Int2Ptr { details: true } => { let mut v = vec![ - ( - None, - format!( - "this program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, which means that Miri might miss pointer bugs in this program" - ), + note!( + "this program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, which means that Miri might miss pointer bugs in this program" ), - ( - None, - format!( - "see https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation" - ), + note!( + "see https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation" ), - ( - None, - format!( - "to ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead" - ), + note!( + "to ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead" ), - ( - None, - format!( - "you can then set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics" - ), + note!( + "you can then set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics" ), ]; if self.borrow_tracker.as_ref().is_some_and(|b| { matches!(b.borrow().borrow_tracker_method(), BorrowTrackerMethod::TreeBorrows) }) { - v.push(( - None, - format!( - "Tree Borrows does not support integer-to-pointer casts, so the program is likely to go wrong when this pointer gets used" - ), - )); + v.push( + note!("Tree Borrows does not support integer-to-pointer casts, so the program is likely to go wrong when this pointer gets used") + ); } else { - v.push(( - None, - format!( - "alternatively, `MIRIFLAGS=-Zmiri-permissive-provenance` disables this warning" - ), - )); + v.push( + note!("alternatively, `MIRIFLAGS=-Zmiri-permissive-provenance` disables this warning") + ); } v } ExternTypeReborrow => { vec![ - ( - None, - format!( - "`extern type` are not compatible with the Stacked Borrows aliasing model implemented by Miri; Miri may miss bugs in this code" - ), + note!( + "`extern type` are not compatible with the Stacked Borrows aliasing model implemented by Miri; Miri may miss bugs in this code" ), - ( - None, - format!( - "try running with `MIRIFLAGS=-Zmiri-tree-borrows` to use the more permissive but also even more experimental Tree Borrows aliasing checks instead" - ), + note!( + "try running with `MIRIFLAGS=-Zmiri-tree-borrows` to use the more permissive but also even more experimental Tree Borrows aliasing checks instead" ), ] } From a52b1d6e29475037a677ceab7d5be5f682c90515 Mon Sep 17 00:00:00 2001 From: tiif Date: Fri, 26 Jul 2024 21:13:58 +0800 Subject: [PATCH 19/33] Let insert_fd takes in FileDescription instead of FileDescriptor --- src/tools/miri/src/machine.rs | 2 +- src/tools/miri/src/shims/unix/fd.rs | 27 ++++++++++--------- src/tools/miri/src/shims/unix/fs.rs | 13 +++------ src/tools/miri/src/shims/unix/linux/epoll.rs | 4 +-- .../miri/src/shims/unix/linux/eventfd.rs | 6 ++--- src/tools/miri/src/shims/unix/socket.rs | 6 ++--- 6 files changed, 24 insertions(+), 34 deletions(-) diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index adb8459356165..e492793a65135 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -660,7 +660,7 @@ impl<'tcx> MiriMachine<'tcx> { tls: TlsData::default(), isolated_op: config.isolated_op, validate: config.validate, - fds: shims::FdTable::new(config.mute_stdout_stderr), + fds: shims::FdTable::init(config.mute_stdout_stderr), dirs: Default::default(), layouts, threads, diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs index de6d27f5290db..0fffecd99d5cb 100644 --- a/src/tools/miri/src/shims/unix/fd.rs +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -192,10 +192,6 @@ impl FileDescription for NullOutput { pub struct FileDescriptor(Rc>>); impl FileDescriptor { - pub fn new(fd: T) -> Self { - FileDescriptor(Rc::new(RefCell::new(Box::new(fd)))) - } - pub fn borrow(&self) -> Ref<'_, dyn FileDescription> { Ref::map(self.0.borrow(), |fd| fd.as_ref()) } @@ -227,20 +223,25 @@ impl VisitProvenance for FdTable { } impl FdTable { - pub(crate) fn new(mute_stdout_stderr: bool) -> FdTable { - let mut fds: BTreeMap<_, FileDescriptor> = BTreeMap::new(); - fds.insert(0i32, FileDescriptor::new(io::stdin())); + fn new() -> Self { + FdTable { fds: BTreeMap::new() } + } + pub(crate) fn init(mute_stdout_stderr: bool) -> FdTable { + let mut fds = FdTable::new(); + fds.insert_fd(io::stdin()); if mute_stdout_stderr { - fds.insert(1i32, FileDescriptor::new(NullOutput)); - fds.insert(2i32, FileDescriptor::new(NullOutput)); + assert_eq!(fds.insert_fd(NullOutput), 1); + assert_eq!(fds.insert_fd(NullOutput), 2); } else { - fds.insert(1i32, FileDescriptor::new(io::stdout())); - fds.insert(2i32, FileDescriptor::new(io::stderr())); + assert_eq!(fds.insert_fd(io::stdout()), 1); + assert_eq!(fds.insert_fd(io::stderr()), 2); } - FdTable { fds } + fds } - pub fn insert_fd(&mut self, file_handle: FileDescriptor) -> i32 { + /// Insert a file descriptor to the FdTable. + pub fn insert_fd(&mut self, fd: T) -> i32 { + let file_handle = FileDescriptor(Rc::new(RefCell::new(Box::new(fd)))); self.insert_fd_with_min_fd(file_handle, 0) } diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index 9ea7f9c37ea16..6923b39733f0b 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -16,8 +16,6 @@ use crate::shims::unix::*; use crate::*; use shims::time::system_time_to_duration; -use self::fd::FileDescriptor; - #[derive(Debug)] struct FileHandle { file: File, @@ -452,10 +450,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { return Ok(-1); } - let fd = options.open(path).map(|file| { - let fh = &mut this.machine.fds; - fh.insert_fd(FileDescriptor::new(FileHandle { file, writable })) - }); + let fd = options + .open(path) + .map(|file| this.machine.fds.insert_fd(FileHandle { file, writable })); this.try_unwrap_io_result(fd) } @@ -1547,9 +1544,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match file { Ok(f) => { - let fh = &mut this.machine.fds; - let fd = - fh.insert_fd(FileDescriptor::new(FileHandle { file: f, writable: true })); + let fd = this.machine.fds.insert_fd(FileHandle { file: f, writable: true }); return Ok(fd); } Err(e) => diff --git a/src/tools/miri/src/shims/unix/linux/epoll.rs b/src/tools/miri/src/shims/unix/linux/epoll.rs index a5661460e95cf..ad35d67876ccb 100644 --- a/src/tools/miri/src/shims/unix/linux/epoll.rs +++ b/src/tools/miri/src/shims/unix/linux/epoll.rs @@ -5,8 +5,6 @@ use rustc_data_structures::fx::FxHashMap; use crate::shims::unix::*; use crate::*; -use self::shims::unix::fd::FileDescriptor; - /// An `Epoll` file descriptor connects file handles and epoll events #[derive(Clone, Debug, Default)] struct Epoll { @@ -66,7 +64,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ); } - let fd = this.machine.fds.insert_fd(FileDescriptor::new(Epoll::default())); + let fd = this.machine.fds.insert_fd(Epoll::default()); Ok(Scalar::from_i32(fd)) } diff --git a/src/tools/miri/src/shims/unix/linux/eventfd.rs b/src/tools/miri/src/shims/unix/linux/eventfd.rs index cae5abca3bd08..0fc28c72bb6fb 100644 --- a/src/tools/miri/src/shims/unix/linux/eventfd.rs +++ b/src/tools/miri/src/shims/unix/linux/eventfd.rs @@ -8,8 +8,6 @@ use rustc_target::abi::Endian; use crate::shims::unix::*; use crate::{concurrency::VClock, *}; -use self::shims::unix::fd::FileDescriptor; - // We'll only do reads and writes in chunks of size u64. const U64_ARRAY_SIZE: usize = mem::size_of::(); @@ -180,11 +178,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { throw_unsup_format!("eventfd: encountered unknown unsupported flags {:#x}", flags); } - let fd = this.machine.fds.insert_fd(FileDescriptor::new(Event { + let fd = this.machine.fds.insert_fd(Event { counter: val.into(), is_nonblock, clock: VClock::default(), - })); + }); Ok(Scalar::from_i32(fd)) } } diff --git a/src/tools/miri/src/shims/unix/socket.rs b/src/tools/miri/src/shims/unix/socket.rs index 6d3d63b4efa02..cc0f932e03829 100644 --- a/src/tools/miri/src/shims/unix/socket.rs +++ b/src/tools/miri/src/shims/unix/socket.rs @@ -7,8 +7,6 @@ use std::rc::{Rc, Weak}; use crate::shims::unix::*; use crate::{concurrency::VClock, *}; -use self::fd::FileDescriptor; - /// The maximum capacity of the socketpair buffer in bytes. /// This number is arbitrary as the value can always /// be configured in the real system. @@ -221,9 +219,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }; let fds = &mut this.machine.fds; - let sv0 = fds.insert_fd(FileDescriptor::new(socketpair_0)); + let sv0 = fds.insert_fd(socketpair_0); + let sv1 = fds.insert_fd(socketpair_1); let sv0 = Scalar::from_int(sv0, sv.layout.size); - let sv1 = fds.insert_fd(FileDescriptor::new(socketpair_1)); let sv1 = Scalar::from_int(sv1, sv.layout.size); this.write_scalar(sv0, &sv)?; From 80a32f86187f897cc075a314cd689c6bd45c4671 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Sat, 27 Jul 2024 05:14:59 +0000 Subject: [PATCH 20/33] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index e1a6084b22eda..58ec4e10856df 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -72d73cec61aa8f85901358cd5d386d5dd066fe52 +a526d7ce45fd2284e0e7c7556ccba2425b9d25e5 From 822286f0758bea84b798e494b5b6103d288a3221 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Jul 2024 08:31:07 +0200 Subject: [PATCH 21/33] fix clippy --- src/tools/miri/src/shims/x86/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs index 0bbf2a8e13e9a..1bd32fce8bd9e 100644 --- a/src/tools/miri/src/shims/x86/mod.rs +++ b/src/tools/miri/src/shims/x86/mod.rs @@ -1178,7 +1178,7 @@ fn pclmulqdq<'tcx>( // if the i-th bit in right is set if (right & (1 << i)) != 0 { // xor result with `left` shifted to the left by i positions - result ^= (left as u128) << i; + result ^= u128::from(left) << i; } } From 5b38b149dc5f8a9aaeb06eac6c6f819e0a17caee Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Jul 2024 17:18:35 +0200 Subject: [PATCH 22/33] miri: fix offset_from behavior on wildcard pointers --- compiler/rustc_const_eval/messages.ftl | 7 +- .../src/interpret/intrinsics.rs | 83 ++++++++----------- .../rustc_const_eval/src/interpret/memory.rs | 19 +++++ .../ptr_offset_from_different_ints.rs | 2 +- .../ptr_offset_from_different_ints.stderr | 4 +- .../ptr_offset_from_unsigned_neg.rs | 3 +- .../ptr_offset_from_unsigned_neg.stderr | 4 +- .../miri/tests/pass/ptr_int_from_exposed.rs | 9 ++ tests/ui/consts/offset_from_ub.rs | 2 +- tests/ui/consts/offset_from_ub.stderr | 6 +- tests/ui/consts/offset_ub.rs | 2 +- 11 files changed, 80 insertions(+), 61 deletions(-) diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index cd269810741e7..a93911225e417 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -233,8 +233,6 @@ const_eval_nullary_intrinsic_fail = const_eval_offset_from_different_allocations = `{$name}` called on pointers into different allocations -const_eval_offset_from_different_integers = - `{$name}` called on different pointers without provenance (i.e., without an associated allocation) const_eval_offset_from_overflow = `{$name}` called when first pointer is too far ahead of second const_eval_offset_from_test = @@ -242,7 +240,10 @@ const_eval_offset_from_test = const_eval_offset_from_underflow = `{$name}` called when first pointer is too far before second const_eval_offset_from_unsigned_overflow = - `ptr_offset_from_unsigned` called when first pointer has smaller offset than second: {$a_offset} < {$b_offset} + `ptr_offset_from_unsigned` called when first pointer has smaller {$is_addr -> + [true] address + *[false] offset + } than second: {$a_offset} < {$b_offset} const_eval_operator_non_const = cannot call non-const operator in {const_eval_const_context}s diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index b227565f8f91a..0b4a21d972cd4 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -243,36 +243,22 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let isize_layout = self.layout_of(self.tcx.types.isize)?; // Get offsets for both that are at least relative to the same base. - let (a_offset, b_offset) = + // With `OFFSET_IS_ADDR` this is trivial; without it we need either + // two integers or two pointers into the same allocation. + let (a_offset, b_offset, is_addr) = if M::Provenance::OFFSET_IS_ADDR { + (a.addr().bytes(), b.addr().bytes(), /*is_addr*/ true) + } else { match (self.ptr_try_get_alloc_id(a), self.ptr_try_get_alloc_id(b)) { (Err(a), Err(b)) => { - // Neither pointer points to an allocation. - // This is okay only if they are the same. - if a != b { - // We'd catch this below in the "dereferenceable" check, but - // show a nicer error for this particular case. - throw_ub_custom!( - fluent::const_eval_offset_from_different_integers, - name = intrinsic_name, - ); - } - // This will always return 0. - (a, b) - } - _ if M::Provenance::OFFSET_IS_ADDR && a.addr() == b.addr() => { - // At least one of the pointers has provenance, but they also point to - // the same address so it doesn't matter; this is fine. `(0, 0)` means - // we pass all the checks below and return 0. - (0, 0) + // Neither pointer points to an allocation, so they are both absolute. + (a, b, /*is_addr*/ true) } - // From here onwards, the pointers are definitely for different addresses - // (or we can't determine their absolute address). (Ok((a_alloc_id, a_offset, _)), Ok((b_alloc_id, b_offset, _))) if a_alloc_id == b_alloc_id => { // Found allocation for both, and it's the same. // Use these offsets for distance calculation. - (a_offset.bytes(), b_offset.bytes()) + (a_offset.bytes(), b_offset.bytes(), /*is_addr*/ false) } _ => { // Not into the same allocation -- this is UB. @@ -281,9 +267,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { name = intrinsic_name, ); } - }; + } + }; - // Compute distance. + // Compute distance: a - b. let dist = { // Addresses are unsigned, so this is a `usize` computation. We have to do the // overflow check separately anyway. @@ -300,6 +287,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { fluent::const_eval_offset_from_unsigned_overflow, a_offset = a_offset, b_offset = b_offset, + is_addr = is_addr, ); } // The signed form of the intrinsic allows this. If we interpret the @@ -328,14 +316,23 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } }; - // Check that the range between them is dereferenceable ("in-bounds or one past the - // end of the same allocation"). This is like the check in ptr_offset_inbounds. - let min_ptr = if dist >= 0 { b } else { a }; - self.check_ptr_access( - min_ptr, - Size::from_bytes(dist.unsigned_abs()), + // Check that the memory between them is dereferenceable at all, starting from the + // base pointer: `dist` is `a - b`, so it is based on `b`. + self.check_ptr_access_signed(b, dist, CheckInAllocMsg::OffsetFromTest)?; + // Then check that this is also dereferenceable from `a`. This ensures that they are + // derived from the same allocation. + self.check_ptr_access_signed( + a, + dist.checked_neg().unwrap(), // i64::MIN is impossible as no allocation can be that large CheckInAllocMsg::OffsetFromTest, - )?; + ) + .map_err(|_| { + // Make the error more specific. + err_ub_custom!( + fluent::const_eval_offset_from_different_allocations, + name = intrinsic_name, + ) + })?; // Perform division by size to compute return value. let ret_layout = if intrinsic_name == sym::ptr_offset_from_unsigned { @@ -582,27 +579,19 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } /// Offsets a pointer by some multiple of its type, returning an error if the pointer leaves its - /// allocation. For integer pointers, we consider each of them their own tiny allocation of size - /// 0, so offset-by-0 (and only 0) is okay -- except that null cannot be offset by _any_ value. + /// allocation. pub fn ptr_offset_inbounds( &self, ptr: Pointer>, offset_bytes: i64, ) -> InterpResult<'tcx, Pointer>> { - // The offset being in bounds cannot rely on "wrapping around" the address space. - // So, first rule out overflows in the pointer arithmetic. - let offset_ptr = ptr.signed_offset(offset_bytes, self)?; - // ptr and offset_ptr must be in bounds of the same allocated object. This means all of the - // memory between these pointers must be accessible. Note that we do not require the - // pointers to be properly aligned (unlike a read/write operation). - let min_ptr = if offset_bytes >= 0 { ptr } else { offset_ptr }; - // This call handles checking for integer/null pointers. - self.check_ptr_access( - min_ptr, - Size::from_bytes(offset_bytes.unsigned_abs()), - CheckInAllocMsg::PointerArithmeticTest, - )?; - Ok(offset_ptr) + // We first compute the pointer with overflow checks, to get a specific error for when it + // overflows (though technically this is redundant with the following inbounds check). + let result = ptr.signed_offset(offset_bytes, self)?; + // The offset must be in bounds starting from `ptr`. + self.check_ptr_access_signed(ptr, offset_bytes, CheckInAllocMsg::PointerArithmeticTest)?; + // Done. + Ok(result) } /// Copy `count*size_of::()` many bytes from `*src` to `*dst`. diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 36fe8dfdd29b7..0d85e8ef66464 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -414,6 +414,25 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Ok(()) } + /// Check whether the given pointer points to live memory for a signed amount of bytes. + /// A negative amounts means that the given range of memory to the left of the pointer + /// needs to be dereferenceable. + pub fn check_ptr_access_signed( + &self, + ptr: Pointer>, + size: i64, + msg: CheckInAllocMsg, + ) -> InterpResult<'tcx> { + if let Ok(size) = u64::try_from(size) { + self.check_ptr_access(ptr, Size::from_bytes(size), msg) + } else { + // Compute the pointer at the beginning of the range, and do the standard + // dereferenceability check from there. + let begin_ptr = ptr.wrapping_signed_offset(size, self); + self.check_ptr_access(begin_ptr, Size::from_bytes(size.unsigned_abs()), msg) + } + } + /// Low-level helper function to check if a ptr is in-bounds and potentially return a reference /// to the allocation it points to. Supports both shared and mutable references, as the actual /// checking is offloaded to a helper closure. diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.rs index 57b4fd0dedb7c..c307dfddb6c1f 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.rs +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.rs @@ -16,6 +16,6 @@ fn main() { let _ = p1.byte_offset_from(p1); // UB because different pointers. - let _ = p1.byte_offset_from(p2); //~ERROR: different pointers without provenance + let _ = p1.byte_offset_from(p2); //~ERROR: no provenance } } diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr index 6e9e5633fecc6..65f1161425ff9 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: `ptr_offset_from` called on different pointers without provenance (i.e., without an associated allocation) +error: Undefined Behavior: out-of-bounds `offset_from`: 0xa[noalloc] is a dangling pointer (it has no provenance) --> $DIR/ptr_offset_from_different_ints.rs:LL:CC | LL | let _ = p1.byte_offset_from(p2); - | ^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on different pointers without provenance (i.e., without an associated allocation) + | ^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from`: 0xa[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs index 06d13d9bdbaf3..13eb5bfb3421d 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs @@ -1,8 +1,9 @@ +//@normalize-stderr-test: "\d+ < \d+" -> "$$ADDR < $$ADDR" #![feature(ptr_sub_ptr)] fn main() { let arr = [0u8; 8]; let ptr1 = arr.as_ptr(); let ptr2 = ptr1.wrapping_add(4); - let _val = unsafe { ptr1.sub_ptr(ptr2) }; //~ERROR: first pointer has smaller offset than second: 0 < 4 + let _val = unsafe { ptr1.sub_ptr(ptr2) }; //~ERROR: first pointer has smaller address than second } diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr index 0b4a9faf1b249..e436f9029d50e 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: `ptr_offset_from_unsigned` called when first pointer has smaller offset than second: 0 < 4 +error: Undefined Behavior: `ptr_offset_from_unsigned` called when first pointer has smaller address than second: $ADDR < $ADDR --> $DIR/ptr_offset_from_unsigned_neg.rs:LL:CC | LL | let _val = unsafe { ptr1.sub_ptr(ptr2) }; - | ^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer has smaller offset than second: 0 < 4 + | ^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer has smaller address than second: $ADDR < $ADDR | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/pass/ptr_int_from_exposed.rs b/src/tools/miri/tests/pass/ptr_int_from_exposed.rs index 5690d7865bbc3..589ef781a91a9 100644 --- a/src/tools/miri/tests/pass/ptr_int_from_exposed.rs +++ b/src/tools/miri/tests/pass/ptr_int_from_exposed.rs @@ -56,9 +56,18 @@ fn ptr_roundtrip_null() { assert_eq!(unsafe { *x_ptr_copy }, 42); } +fn ptr_roundtrip_offset_from() { + let arr = [0; 5]; + let begin = arr.as_ptr(); + let end = begin.wrapping_add(arr.len()); + let end_roundtrip = ptr::with_exposed_provenance::(end.expose_provenance()); + unsafe { end_roundtrip.offset_from(begin) }; +} + fn main() { ptr_roundtrip_out_of_bounds(); ptr_roundtrip_confusion(); ptr_roundtrip_imperfect(); ptr_roundtrip_null(); + ptr_roundtrip_offset_from(); } diff --git a/tests/ui/consts/offset_from_ub.rs b/tests/ui/consts/offset_from_ub.rs index 1506c212fbae8..95b3118f1570a 100644 --- a/tests/ui/consts/offset_from_ub.rs +++ b/tests/ui/consts/offset_from_ub.rs @@ -36,7 +36,7 @@ pub const DIFFERENT_INT: isize = { // offset_from with two different integers: l let ptr1 = 8 as *const u8; let ptr2 = 16 as *const u8; unsafe { ptr_offset_from(ptr2, ptr1) } //~ERROR evaluation of constant value failed - //~| different pointers without provenance + //~| dangling pointer }; const OUT_OF_BOUNDS_1: isize = { diff --git a/tests/ui/consts/offset_from_ub.stderr b/tests/ui/consts/offset_from_ub.stderr index 7b623126d54f2..0a860f42c649c 100644 --- a/tests/ui/consts/offset_from_ub.stderr +++ b/tests/ui/consts/offset_from_ub.stderr @@ -27,7 +27,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/offset_from_ub.rs:38:14 | LL | unsafe { ptr_offset_from(ptr2, ptr1) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on different pointers without provenance (i.e., without an associated allocation) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from`: 0x8[noalloc] is a dangling pointer (it has no provenance) error[E0080]: evaluation of constant value failed --> $DIR/offset_from_ub.rs:47:14 @@ -80,7 +80,7 @@ LL | unsafe { ptr_offset_from_unsigned(ptr2, ptr1) } error[E0080]: evaluation of constant value failed --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | - = note: `ptr_offset_from` called on different pointers without provenance (i.e., without an associated allocation) + = note: out-of-bounds `offset_from`: null pointer is a dangling pointer (it has no provenance) | note: inside `std::ptr::const_ptr::::offset_from` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -93,7 +93,7 @@ LL | unsafe { ptr2.offset_from(ptr1) } error[E0080]: evaluation of constant value failed --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | - = note: `ptr_offset_from` called on different pointers without provenance (i.e., without an associated allocation) + = note: `ptr_offset_from` called when first pointer is too far before second | note: inside `std::ptr::const_ptr::::offset_from` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL diff --git a/tests/ui/consts/offset_ub.rs b/tests/ui/consts/offset_ub.rs index ebc7019a75aa8..9a8f756749b70 100644 --- a/tests/ui/consts/offset_ub.rs +++ b/tests/ui/consts/offset_ub.rs @@ -1,6 +1,6 @@ use std::ptr; - +//@ normalize-stderr-test: "0xf+" -> "0xf..f" //@ normalize-stderr-test: "0x7f+" -> "0x7f..f" From f8ebe8d783e20c44508fab32b708f1b9d9a4bf13 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Jul 2024 18:09:50 +0200 Subject: [PATCH 23/33] improve dangling/oob errors and make them more uniform --- compiler/rustc_const_eval/messages.ftl | 27 ++++++++---- compiler/rustc_const_eval/src/errors.rs | 42 ++++++++++++------- .../rustc_const_eval/src/interpret/memory.rs | 12 ++++-- .../src/interpret/validity.rs | 8 ++-- .../rustc_middle/src/mir/interpret/error.rs | 11 +++-- .../rustc_middle/src/mir/interpret/pointer.rs | 9 ++-- .../miri/tests/fail-dep/libc/affinity.stderr | 4 +- .../miri/tests/fail-dep/libc/memchr_null.rs | 2 +- .../tests/fail-dep/libc/memchr_null.stderr | 4 +- .../miri/tests/fail-dep/libc/memcmp_null.rs | 2 +- .../tests/fail-dep/libc/memcmp_null.stderr | 4 +- .../tests/fail-dep/libc/memcmp_zero.stderr | 4 +- .../tests/fail-dep/libc/memcpy_zero.stderr | 4 +- .../miri/tests/fail-dep/libc/memrchr_null.rs | 2 +- .../tests/fail-dep/libc/memrchr_null.stderr | 4 +- .../fail/both_borrows/issue-miri-1050-1.rs | 2 +- .../issue-miri-1050-1.stack.stderr | 4 +- .../issue-miri-1050-1.tree.stderr | 4 +- .../issue-miri-1050-2.stack.stderr | 4 +- .../issue-miri-1050-2.tree.stderr | 4 +- .../dangling_pointer_to_raw_pointer.stderr | 4 +- .../deref-invalid-ptr.stderr | 4 +- .../dangling_pointers/null_pointer_deref.rs | 2 +- .../null_pointer_deref.stderr | 4 +- .../dangling_pointers/null_pointer_write.rs | 2 +- .../null_pointer_write.stderr | 4 +- .../out_of_bounds_project.stderr | 4 +- .../dangling_pointers/out_of_bounds_read.rs | 2 +- .../out_of_bounds_read.stderr | 4 +- .../dangling_pointers/out_of_bounds_write.rs | 2 +- .../out_of_bounds_write.stderr | 4 +- .../storage_dead_dangling.stderr | 4 +- .../wild_pointer_deref.stderr | 4 +- .../cast_int_to_fn_ptr.stderr | 4 +- .../fail/intrinsics/out_of_bounds_ptr_1.rs | 2 +- .../intrinsics/out_of_bounds_ptr_1.stderr | 4 +- .../fail/intrinsics/out_of_bounds_ptr_3.rs | 2 +- .../intrinsics/out_of_bounds_ptr_3.stderr | 4 +- .../ptr_offset_from_different_ints.stderr | 4 +- .../intrinsics/ptr_offset_int_plus_int.stderr | 4 +- .../intrinsics/ptr_offset_int_plus_ptr.rs | 1 + .../intrinsics/ptr_offset_int_plus_ptr.stderr | 4 +- .../miri/tests/fail/intrinsics/simd-gather.rs | 3 +- .../tests/fail/intrinsics/simd-gather.stderr | 4 +- .../tests/fail/intrinsics/simd-scatter.rs | 2 +- .../tests/fail/intrinsics/simd-scatter.stderr | 4 +- .../pointer_partial_overwrite.stderr | 4 +- .../provenance/provenance_transmute.stderr | 4 +- .../fail/provenance/ptr_int_unexposed.stderr | 4 +- .../tests/fail/provenance/ptr_invalid.stderr | 4 +- .../fail/provenance/ptr_invalid_offset.stderr | 4 +- .../tests/fail/reading_half_a_pointer.stderr | 4 +- .../fail/shims/backtrace/bad-backtrace-ptr.rs | 2 +- .../shims/backtrace/bad-backtrace-ptr.stderr | 4 +- src/tools/miri/tests/fail/zst_local_oob.rs | 2 +- .../miri/tests/fail/zst_local_oob.stderr | 4 +- tests/ui/const-ptr/forbidden_slices.stderr | 4 +- tests/ui/const-ptr/out_of_bounds_read.stderr | 6 +-- tests/ui/consts/const-compare-bytes-ub.stderr | 10 ++--- tests/ui/consts/const-deref-ptr.stderr | 2 +- .../const-eval/const_raw_ptr_ops2.stderr | 4 +- .../const-eval/nonnull_as_ref_ub.stderr | 2 +- .../consts/const-eval/raw-bytes.32bit.stderr | 2 +- .../consts/const-eval/raw-bytes.64bit.stderr | 2 +- tests/ui/consts/const-eval/raw-pointer-ub.rs | 2 +- .../consts/const-eval/raw-pointer-ub.stderr | 2 +- tests/ui/consts/const-eval/ub-nonnull.stderr | 2 +- tests/ui/consts/const-eval/ub-wide-ptr.stderr | 4 +- tests/ui/consts/copy-intrinsic.rs | 4 +- tests/ui/consts/copy-intrinsic.stderr | 4 +- tests/ui/consts/offset_from_ub.rs | 5 ++- tests/ui/consts/offset_from_ub.stderr | 36 ++++++++-------- tests/ui/consts/offset_ub.rs | 1 + tests/ui/consts/offset_ub.stderr | 34 +++++++-------- tests/ui/error-codes/E0396-fixed.stderr | 2 +- 75 files changed, 225 insertions(+), 182 deletions(-) diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index a93911225e417..43f405b223504 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -45,9 +45,9 @@ const_eval_copy_nonoverlapping_overlapping = `copy_nonoverlapping` called on overlapping ranges const_eval_dangling_int_pointer = - {$bad_pointer_message}: {$pointer} is a dangling pointer (it has no provenance) + {$bad_pointer_message}: {const_eval_expected_inbounds_pointer}, but got {$pointer} which is a dangling pointer (it has no provenance) const_eval_dangling_null_pointer = - {$bad_pointer_message}: null pointer is a dangling pointer (it has no provenance) + {$bad_pointer_message}: {const_eval_expected_inbounds_pointer}, but got a null pointer const_eval_dangling_ptr_in_final = encountered dangling pointer in final value of {const_eval_intern_kind} const_eval_dead_local = @@ -87,6 +87,13 @@ const_eval_error = {$error_kind -> const_eval_exact_div_has_remainder = exact_div: {$a} cannot be divided by {$b} without remainder +const_eval_expected_inbounds_pointer = + expected {$inbounds_size -> + [0] a pointer to some allocation + [1] a pointer to 1 byte of memory + *[x] a pointer to {$inbounds_size} bytes of memory + } + const_eval_extern_static = cannot access extern static ({$did}) const_eval_extern_type_field = `extern type` field does not have a known offset @@ -265,10 +272,16 @@ const_eval_pointer_arithmetic_overflow = overflowing in-bounds pointer arithmetic const_eval_pointer_arithmetic_test = out-of-bounds pointer arithmetic const_eval_pointer_out_of_bounds = - {$bad_pointer_message}: {$alloc_id} has size {$alloc_size}, so pointer to {$ptr_size} {$ptr_size -> - [1] byte - *[many] bytes - } starting at offset {$ptr_offset} is out-of-bounds + {$bad_pointer_message}: {const_eval_expected_inbounds_pointer}, but got {$pointer} {$ptr_offset_is_neg -> + [true] which points to before the beginning of the allocation + *[false] {$alloc_size_minus_ptr_offset -> + [0] which is at or beyond the end of the allocation of size {$alloc_size -> + [1] 1 byte + *[x] {$alloc_size} bytes + } + *[x] and there are only {$alloc_size_minus_ptr_offset} bytes starting at that pointer + } + } const_eval_pointer_use_after_free = {$bad_pointer_message}: {$alloc_id} has been freed, so this pointer is dangling const_eval_ptr_as_bytes_1 = @@ -466,5 +479,3 @@ const_eval_write_through_immutable_pointer = const_eval_write_to_read_only = writing to {$allocation} which is read-only -const_eval_zst_pointer_out_of_bounds = - {$bad_pointer_message}: {$alloc_id} has size {$alloc_size}, so pointer at offset {$ptr_offset} is out-of-bounds diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 292d6ba9d08a4..922225e22d909 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -7,9 +7,9 @@ use rustc_errors::{ use rustc_hir::ConstContext; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::mir::interpret::{ - CheckInAllocMsg, ExpectedKind, InterpError, InvalidMetaKind, InvalidProgramInfo, Misalignment, - PointerKind, ResourceExhaustionInfo, UndefinedBehaviorInfo, UnsupportedOpInfo, - ValidationErrorInfo, + CheckInAllocMsg, CtfeProvenance, ExpectedKind, InterpError, InvalidMetaKind, + InvalidProgramInfo, Misalignment, Pointer, PointerKind, ResourceExhaustionInfo, + UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo, }; use rustc_middle::ty::{self, Mutability, Ty}; use rustc_span::Span; @@ -488,10 +488,9 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { InvalidMeta(InvalidMetaKind::TooBig) => const_eval_invalid_meta, UnterminatedCString(_) => const_eval_unterminated_c_string, PointerUseAfterFree(_, _) => const_eval_pointer_use_after_free, - PointerOutOfBounds { ptr_size: Size::ZERO, .. } => const_eval_zst_pointer_out_of_bounds, PointerOutOfBounds { .. } => const_eval_pointer_out_of_bounds, - DanglingIntPointer(0, _) => const_eval_dangling_null_pointer, - DanglingIntPointer(_, _) => const_eval_dangling_int_pointer, + DanglingIntPointer { addr: 0, .. } => const_eval_dangling_null_pointer, + DanglingIntPointer { .. } => const_eval_dangling_int_pointer, AlignmentCheckFailed { .. } => const_eval_alignment_check_failed, WriteToReadOnly(_) => const_eval_write_to_read_only, DerefFunctionPointer(_) => const_eval_deref_function_pointer, @@ -573,18 +572,33 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { diag.arg("alloc_id", alloc_id) .arg("bad_pointer_message", bad_pointer_message(msg, dcx)); } - PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size, msg } => { - diag.arg("alloc_id", alloc_id) - .arg("alloc_size", alloc_size.bytes()) - .arg("ptr_offset", ptr_offset) - .arg("ptr_size", ptr_size.bytes()) + PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, inbounds_size, msg } => { + diag.arg("alloc_size", alloc_size.bytes()) + .arg("inbounds_size", inbounds_size.bytes()) .arg("bad_pointer_message", bad_pointer_message(msg, dcx)); + diag.arg( + "pointer", + Pointer::new( + Some(CtfeProvenance::from(alloc_id)), + Size::from_bytes(ptr_offset as u64), + ) + .to_string(), + ); + diag.arg("ptr_offset_is_neg", ptr_offset < 0); + diag.arg( + "alloc_size_minus_ptr_offset", + alloc_size.bytes().saturating_sub(ptr_offset as u64), + ); } - DanglingIntPointer(ptr, msg) => { - if ptr != 0 { - diag.arg("pointer", format!("{ptr:#x}[noalloc]")); + DanglingIntPointer { addr, inbounds_size, msg } => { + if addr != 0 { + diag.arg( + "pointer", + Pointer::>::from_addr_invalid(addr).to_string(), + ); } + diag.arg("inbounds_size", inbounds_size.bytes()); diag.arg("bad_pointer_message", bad_pointer_message(msg, dcx)); } AlignmentCheckFailed(Misalignment { required, has }, msg) => { diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 0d85e8ef66464..f49a0ed727a8d 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -459,7 +459,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Ok(match self.ptr_try_get_alloc_id(ptr) { Err(addr) => { // We couldn't get a proper allocation. - throw_ub!(DanglingIntPointer(addr, msg)); + throw_ub!(DanglingIntPointer { addr, inbounds_size: size, msg }); } Ok((alloc_id, offset, prov)) => { let (alloc_size, _alloc_align, ret_val) = alloc_size(alloc_id, offset, prov)?; @@ -470,7 +470,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { alloc_id, alloc_size, ptr_offset: self.target_usize_to_isize(offset.bytes()), - ptr_size: size, + inbounds_size: size, msg, }) } @@ -1443,7 +1443,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ptr: Pointer>, ) -> InterpResult<'tcx, (AllocId, Size, M::ProvenanceExtra)> { self.ptr_try_get_alloc_id(ptr).map_err(|offset| { - err_ub!(DanglingIntPointer(offset, CheckInAllocMsg::InboundsTest)).into() + err_ub!(DanglingIntPointer { + addr: offset, + // We don't know the actually required size. + inbounds_size: Size::ZERO, + msg: CheckInAllocMsg::InboundsTest + }) + .into() }) } } diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 3dc3e6c883320..879f9205cbf41 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -348,7 +348,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { try_validation!( self.ecx.get_ptr_vtable_ty(vtable, Some(data)), self.path, - Ub(DanglingIntPointer(..) | InvalidVTablePointer(..)) => + Ub(DanglingIntPointer{ .. } | InvalidVTablePointer(..)) => InvalidVTablePtr { value: format!("{vtable}") }, Ub(InvalidVTableTrait { expected_trait, vtable_trait }) => { InvalidMetaWrongTrait { expected_trait, vtable_trait: *vtable_trait } @@ -405,8 +405,8 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { CheckInAllocMsg::InboundsTest, // will anyway be replaced by validity message ), self.path, - Ub(DanglingIntPointer(0, _)) => NullPtr { ptr_kind }, - Ub(DanglingIntPointer(i, _)) => DanglingPtrNoProvenance { + Ub(DanglingIntPointer { addr: 0, .. }) => NullPtr { ptr_kind }, + Ub(DanglingIntPointer { addr: i, .. }) => DanglingPtrNoProvenance { ptr_kind, // FIXME this says "null pointer" when null but we need translate pointer: format!("{}", Pointer::>::from_addr_invalid(*i)) @@ -605,7 +605,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { let _fn = try_validation!( self.ecx.get_ptr_fn(ptr), self.path, - Ub(DanglingIntPointer(..) | InvalidFunctionPointer(..)) => + Ub(DanglingIntPointer{ .. } | InvalidFunctionPointer(..)) => InvalidFnPtr { value: format!("{ptr}") }, ); // FIXME: Check if the signature matches diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 9df19565ab383..68676e862ef0a 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -329,16 +329,21 @@ pub enum UndefinedBehaviorInfo<'tcx> { /// Using a pointer after it got freed. PointerUseAfterFree(AllocId, CheckInAllocMsg), /// Used a pointer outside the bounds it is valid for. - /// (If `ptr_size > 0`, determines the size of the memory range that was expected to be in-bounds.) PointerOutOfBounds { alloc_id: AllocId, alloc_size: Size, ptr_offset: i64, - ptr_size: Size, + /// The size of the memory range that was expected to be in-bounds. + inbounds_size: Size, msg: CheckInAllocMsg, }, /// Using an integer as a pointer in the wrong way. - DanglingIntPointer(u64, CheckInAllocMsg), + DanglingIntPointer { + addr: u64, + /// The size of the memory range that was expected to be in-bounds (or 0 if we don't know). + inbounds_size: Size, + msg: CheckInAllocMsg, + }, /// Used a pointer with bad alignment. AlignmentCheckFailed(Misalignment, CheckAlignMsg), /// Writing to read-only memory. diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs index a0acacc844fd5..074245fcd32ad 100644 --- a/compiler/rustc_middle/src/mir/interpret/pointer.rs +++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs @@ -180,9 +180,12 @@ impl Provenance for CtfeProvenance { fn fmt(ptr: &Pointer, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Print AllocId. fmt::Debug::fmt(&ptr.provenance.alloc_id(), f)?; // propagates `alternate` flag - // Print offset only if it is non-zero. - if ptr.offset.bytes() > 0 { - write!(f, "+{:#x}", ptr.offset.bytes())?; + // Print offset only if it is non-zero. Print it signed. + let signed_offset = ptr.offset.bytes() as i64; + if signed_offset > 0 { + write!(f, "+{:#x}", signed_offset)?; + } else if signed_offset < 0 { + write!(f, "-{:#x}", signed_offset.unsigned_abs())?; } // Print immutable status. if ptr.provenance.immutable() { diff --git a/src/tools/miri/tests/fail-dep/libc/affinity.stderr b/src/tools/miri/tests/fail-dep/libc/affinity.stderr index c01f15800fac3..b9f79fdda89c4 100644 --- a/src/tools/miri/tests/fail-dep/libc/affinity.stderr +++ b/src/tools/miri/tests/fail-dep/libc/affinity.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: ALLOC has size 128, so pointer to 129 bytes starting at offset 0 is out-of-bounds +error: Undefined Behavior: memory access failed: expected a pointer to 129 bytes of memory, but got ALLOC and there are only 128 bytes starting at that pointer --> $DIR/affinity.rs:LL:CC | LL | let err = unsafe { sched_setaffinity(PID, size_of::() + 1, &cpuset) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC has size 128, so pointer to 129 bytes starting at offset 0 is out-of-bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 129 bytes of memory, but got ALLOC and there are only 128 bytes starting at that pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail-dep/libc/memchr_null.rs b/src/tools/miri/tests/fail-dep/libc/memchr_null.rs index 672cc10cd6304..b6b4b62e62107 100644 --- a/src/tools/miri/tests/fail-dep/libc/memchr_null.rs +++ b/src/tools/miri/tests/fail-dep/libc/memchr_null.rs @@ -3,6 +3,6 @@ use std::ptr; // null is explicitly called out as UB in the C docs. fn main() { unsafe { - libc::memchr(ptr::null(), 0, 0); //~ERROR: dangling + libc::memchr(ptr::null(), 0, 0); //~ERROR: null pointer } } diff --git a/src/tools/miri/tests/fail-dep/libc/memchr_null.stderr b/src/tools/miri/tests/fail-dep/libc/memchr_null.stderr index b76722f5f8f19..f03ae33ed9f39 100644 --- a/src/tools/miri/tests/fail-dep/libc/memchr_null.stderr +++ b/src/tools/miri/tests/fail-dep/libc/memchr_null.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance) +error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer --> $DIR/memchr_null.rs:LL:CC | LL | libc::memchr(ptr::null(), 0, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail-dep/libc/memcmp_null.rs b/src/tools/miri/tests/fail-dep/libc/memcmp_null.rs index 066af4a8ae3c9..0e204aa7f0940 100644 --- a/src/tools/miri/tests/fail-dep/libc/memcmp_null.rs +++ b/src/tools/miri/tests/fail-dep/libc/memcmp_null.rs @@ -3,6 +3,6 @@ use std::ptr; // null is explicitly called out as UB in the C docs. fn main() { unsafe { - libc::memcmp(ptr::null(), ptr::null(), 0); //~ERROR: dangling + libc::memcmp(ptr::null(), ptr::null(), 0); //~ERROR: null pointer } } diff --git a/src/tools/miri/tests/fail-dep/libc/memcmp_null.stderr b/src/tools/miri/tests/fail-dep/libc/memcmp_null.stderr index 5c6ba4fd97979..4bca5a3db0722 100644 --- a/src/tools/miri/tests/fail-dep/libc/memcmp_null.stderr +++ b/src/tools/miri/tests/fail-dep/libc/memcmp_null.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance) +error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer --> $DIR/memcmp_null.rs:LL:CC | LL | libc::memcmp(ptr::null(), ptr::null(), 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail-dep/libc/memcmp_zero.stderr b/src/tools/miri/tests/fail-dep/libc/memcmp_zero.stderr index 4ab37ab569fe4..6adaaeb3dbf1e 100644 --- a/src/tools/miri/tests/fail-dep/libc/memcmp_zero.stderr +++ b/src/tools/miri/tests/fail-dep/libc/memcmp_zero.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: 0x2a[noalloc] is a dangling pointer (it has no provenance) +error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/memcmp_zero.rs:LL:CC | LL | libc::memcmp(ptr.cast(), ptr.cast(), 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: 0x2a[noalloc] is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail-dep/libc/memcpy_zero.stderr b/src/tools/miri/tests/fail-dep/libc/memcpy_zero.stderr index 3e1ee7b86e31f..b2da332df2149 100644 --- a/src/tools/miri/tests/fail-dep/libc/memcpy_zero.stderr +++ b/src/tools/miri/tests/fail-dep/libc/memcpy_zero.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: 0x17[noalloc] is a dangling pointer (it has no provenance) +error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got 0x17[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/memcpy_zero.rs:LL:CC | LL | libc::memcpy(to.cast(), from.cast(), 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: 0x17[noalloc] is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got 0x17[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail-dep/libc/memrchr_null.rs b/src/tools/miri/tests/fail-dep/libc/memrchr_null.rs index f06336b129959..1fe637d6ce7e9 100644 --- a/src/tools/miri/tests/fail-dep/libc/memrchr_null.rs +++ b/src/tools/miri/tests/fail-dep/libc/memrchr_null.rs @@ -6,6 +6,6 @@ use std::ptr; // null is explicitly called out as UB in the C docs. fn main() { unsafe { - libc::memrchr(ptr::null(), 0, 0); //~ERROR: dangling + libc::memrchr(ptr::null(), 0, 0); //~ERROR: null pointer } } diff --git a/src/tools/miri/tests/fail-dep/libc/memrchr_null.stderr b/src/tools/miri/tests/fail-dep/libc/memrchr_null.stderr index 0cc7ac19febc4..a9ed58d61bb35 100644 --- a/src/tools/miri/tests/fail-dep/libc/memrchr_null.stderr +++ b/src/tools/miri/tests/fail-dep/libc/memrchr_null.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance) +error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer --> $DIR/memrchr_null.rs:LL:CC | LL | libc::memrchr(ptr::null(), 0, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.rs b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.rs index 424aace239a21..49de3dd0b1052 100644 --- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.rs +++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.rs @@ -1,6 +1,6 @@ //@revisions: stack tree //@[tree]compile-flags: -Zmiri-tree-borrows -//@error-in-other-file: pointer to 4 bytes starting at offset 0 is out-of-bounds +//@error-in-other-file: expected a pointer to 4 bytes of memory fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.stack.stderr b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.stack.stderr index be01c5cc840f8..07bb3293989e7 100644 --- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.stack.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: ALLOC has size 2, so pointer to 4 bytes starting at offset 0 is out-of-bounds +error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got ALLOC and there are only 2 bytes starting at that pointer --> RUSTLIB/alloc/src/boxed.rs:LL:CC | LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: ALLOC has size 2, so pointer to 4 bytes starting at offset 0 is out-of-bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got ALLOC and there are only 2 bytes starting at that pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.tree.stderr b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.tree.stderr index be01c5cc840f8..07bb3293989e7 100644 --- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.tree.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: ALLOC has size 2, so pointer to 4 bytes starting at offset 0 is out-of-bounds +error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got ALLOC and there are only 2 bytes starting at that pointer --> RUSTLIB/alloc/src/boxed.rs:LL:CC | LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: ALLOC has size 2, so pointer to 4 bytes starting at offset 0 is out-of-bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got ALLOC and there are only 2 bytes starting at that pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.stack.stderr b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.stack.stderr index e96e641bb0d38..04494b5256172 100644 --- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.stack.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: 0x4[noalloc] is a dangling pointer (it has no provenance) +error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x4[noalloc] which is a dangling pointer (it has no provenance) --> RUSTLIB/alloc/src/boxed.rs:LL:CC | LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: 0x4[noalloc] is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x4[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.tree.stderr b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.tree.stderr index e96e641bb0d38..04494b5256172 100644 --- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.tree.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: 0x4[noalloc] is a dangling pointer (it has no provenance) +error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x4[noalloc] which is a dangling pointer (it has no provenance) --> RUSTLIB/alloc/src/boxed.rs:LL:CC | LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: 0x4[noalloc] is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x4[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr index 37f2bb3955763..a5c031b949643 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: 0x10[noalloc] is a dangling pointer (it has no provenance) +error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x10[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/dangling_pointer_to_raw_pointer.rs:LL:CC | LL | unsafe { &(*x).0 as *const i32 } - | ^^^^^^^ out-of-bounds pointer use: 0x10[noalloc] is a dangling pointer (it has no provenance) + | ^^^^^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x10[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/deref-invalid-ptr.stderr b/src/tools/miri/tests/fail/dangling_pointers/deref-invalid-ptr.stderr index 377022fa97f36..d989bff4516f2 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/deref-invalid-ptr.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/deref-invalid-ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: 0x10[noalloc] is a dangling pointer (it has no provenance) +error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x10[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/deref-invalid-ptr.rs:LL:CC | LL | let _y = unsafe { &*x as *const u32 }; - | ^^^ out-of-bounds pointer use: 0x10[noalloc] is a dangling pointer (it has no provenance) + | ^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x10[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.rs b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.rs index a0773c63cf6bf..dee05952a9936 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.rs +++ b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.rs @@ -1,5 +1,5 @@ #[allow(deref_nullptr)] fn main() { - let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR: null pointer is a dangling pointer + let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR: null pointer panic!("this should never print: {}", x); } diff --git a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.stderr b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.stderr index a18f0f20fc015..1b97265eb32f6 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got a null pointer --> $DIR/null_pointer_deref.rs:LL:CC | LL | let x: i32 = unsafe { *std::ptr::null() }; - | ^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got a null pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.rs b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.rs index 954596f57542e..61f5ef572cf3c 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.rs +++ b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.rs @@ -1,4 +1,4 @@ #[allow(deref_nullptr)] fn main() { - unsafe { *std::ptr::null_mut() = 0i32 }; //~ ERROR: null pointer is a dangling pointer + unsafe { *std::ptr::null_mut() = 0i32 }; //~ ERROR: null pointer } diff --git a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.stderr b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.stderr index 01d4d12a002dd..3d75e7a0254b6 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got a null pointer --> $DIR/null_pointer_write.rs:LL:CC | LL | unsafe { *std::ptr::null_mut() = 0i32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got a null pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.stderr b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.stderr index 4195c68d500dd..bdd245e184948 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds +error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to 8 bytes of memory, but got ALLOC and there are only 4 bytes starting at that pointer --> $DIR/out_of_bounds_project.rs:LL:CC | LL | let _field = addr_of!((*ptr).2); - | ^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds + | ^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to 8 bytes of memory, but got ALLOC and there are only 4 bytes starting at that pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.rs b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.rs index 658fbd16c2e8d..595a229baa5aa 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.rs +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.rs @@ -1,6 +1,6 @@ fn main() { let v: Vec = vec![1, 2]; // This read is also misaligned. We make sure that the OOB message has priority. - let x = unsafe { *v.as_ptr().wrapping_byte_add(5) }; //~ ERROR: out-of-bounds + let x = unsafe { *v.as_ptr().wrapping_byte_add(5) }; //~ ERROR: expected a pointer to 2 bytes of memory panic!("this should never print: {}", x); } diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.stderr b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.stderr index 37dbea37ce2dc..8a774c21bb7c1 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: ALLOC has size 4, so pointer to 2 bytes starting at offset 5 is out-of-bounds +error: Undefined Behavior: memory access failed: expected a pointer to 2 bytes of memory, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes --> $DIR/out_of_bounds_read.rs:LL:CC | LL | let x = unsafe { *v.as_ptr().wrapping_byte_add(5) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC has size 4, so pointer to 2 bytes starting at offset 5 is out-of-bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 2 bytes of memory, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.rs b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.rs index 2ff537b1ffc5f..054e1c66cc18d 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.rs +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.rs @@ -1,5 +1,5 @@ fn main() { let mut v: Vec = vec![1, 2]; // This read is also misaligned. We make sure that the OOB message has priority. - unsafe { *v.as_mut_ptr().wrapping_byte_add(5) = 0 }; //~ ERROR: out-of-bounds + unsafe { *v.as_mut_ptr().wrapping_byte_add(5) = 0 }; //~ ERROR: expected a pointer to 2 bytes of memory } diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.stderr b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.stderr index 97b3f3ebe7b5c..6ae9f05d17381 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: ALLOC has size 4, so pointer to 2 bytes starting at offset 5 is out-of-bounds +error: Undefined Behavior: memory access failed: expected a pointer to 2 bytes of memory, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes --> $DIR/out_of_bounds_write.rs:LL:CC | LL | unsafe { *v.as_mut_ptr().wrapping_byte_add(5) = 0 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC has size 4, so pointer to 2 bytes starting at offset 5 is out-of-bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 2 bytes of memory, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr index 73c3ff1ee0512..2d4fbafd8b7f6 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: $HEX[noalloc] is a dangling pointer (it has no provenance) +error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/storage_dead_dangling.rs:LL:CC | LL | let _ref = unsafe { &mut *(LEAK as *mut i32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: $HEX[noalloc] is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/wild_pointer_deref.stderr b/src/tools/miri/tests/fail/dangling_pointers/wild_pointer_deref.stderr index b7492a09dd090..1d8eed3d30a7c 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/wild_pointer_deref.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/wild_pointer_deref.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: 0x2c[noalloc] is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got 0x2c[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/wild_pointer_deref.rs:LL:CC | LL | let x = unsafe { *p }; - | ^^ memory access failed: 0x2c[noalloc] is a dangling pointer (it has no provenance) + | ^^ memory access failed: expected a pointer to 4 bytes of memory, but got 0x2c[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr b/src/tools/miri/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr index 7274f62b4d7c0..347afa77053ee 100644 --- a/src/tools/miri/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr +++ b/src/tools/miri/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: 0x2a[noalloc] is a dangling pointer (it has no provenance) +error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/cast_int_to_fn_ptr.rs:LL:CC | LL | g(42) - | ^^^^^ out-of-bounds pointer use: 0x2a[noalloc] is a dangling pointer (it has no provenance) + | ^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_1.rs b/src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_1.rs index b6a110ee84d2c..f337090aa1e36 100644 --- a/src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_1.rs +++ b/src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_1.rs @@ -2,6 +2,6 @@ fn main() { let v = [0i8; 4]; let x = &v as *const i8; // The error is inside another function, so we cannot match it by line - let x = unsafe { x.offset(5) }; //~ERROR: pointer to 5 bytes starting at offset 0 is out-of-bounds + let x = unsafe { x.offset(5) }; //~ERROR: expected a pointer to 5 bytes of memory panic!("this should never print: {:?}", x); } diff --git a/src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr b/src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr index cc8cca70ddb9f..ddc5ae8efbc01 100644 --- a/src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr +++ b/src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer to 5 bytes starting at offset 0 is out-of-bounds +error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to 5 bytes of memory, but got ALLOC and there are only 4 bytes starting at that pointer --> $DIR/out_of_bounds_ptr_1.rs:LL:CC | LL | let x = unsafe { x.offset(5) }; - | ^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer to 5 bytes starting at offset 0 is out-of-bounds + | ^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to 5 bytes of memory, but got ALLOC and there are only 4 bytes starting at that pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_3.rs b/src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_3.rs index 701bc33a645e1..fc9fb3d35d610 100644 --- a/src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_3.rs +++ b/src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_3.rs @@ -1,6 +1,6 @@ fn main() { let v = [0i8; 4]; let x = &v as *const i8; - let x = unsafe { x.offset(-1) }; //~ERROR: pointer to 1 byte starting at offset -1 is out-of-bounds + let x = unsafe { x.offset(-1) }; //~ERROR: expected a pointer to 1 byte of memory panic!("this should never print: {:?}", x); } diff --git a/src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr b/src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr index 236b51e82e594..88963e712f4cc 100644 --- a/src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr +++ b/src/tools/miri/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer to 1 byte starting at offset -1 is out-of-bounds +error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to 1 byte of memory, but got ALLOC-0x1 which points to before the beginning of the allocation --> $DIR/out_of_bounds_ptr_3.rs:LL:CC | LL | let x = unsafe { x.offset(-1) }; - | ^^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer to 1 byte starting at offset -1 is out-of-bounds + | ^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to 1 byte of memory, but got ALLOC-0x1 which points to before the beginning of the allocation | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr index 65f1161425ff9..649075dbc55de 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds `offset_from`: 0xa[noalloc] is a dangling pointer (it has no provenance) +error: Undefined Behavior: out-of-bounds `offset_from`: expected a pointer to 1 byte of memory, but got 0xa[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/ptr_offset_from_different_ints.rs:LL:CC | LL | let _ = p1.byte_offset_from(p2); - | ^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from`: 0xa[noalloc] is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from`: expected a pointer to 1 byte of memory, but got 0xa[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr index e03abfb1a2fcd..8d37da6506133 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance) +error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to 1 byte of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/ptr_offset_int_plus_int.rs:LL:CC | LL | let _val = (1 as *mut u8).offset(1); - | ^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to 1 byte of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs index fd3c9b44615c2..c4b6f69dd2be6 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs @@ -1,4 +1,5 @@ //@compile-flags: -Zmiri-permissive-provenance +//@normalize-stderr-test: "to \d+ bytes of memory" -> "to $$BYTES bytes of memory" fn main() { let ptr = Box::into_raw(Box::new(0u32)); diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr index 03ae9bd141c4a..2cd02bee2ca18 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance) +error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to $BYTES bytes of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/ptr_offset_int_plus_ptr.rs:LL:CC | LL | let _val = (1 as *mut u8).offset(ptr as isize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to $BYTES bytes of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/intrinsics/simd-gather.rs b/src/tools/miri/tests/fail/intrinsics/simd-gather.rs index ceb7beebd8aba..b837395245179 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-gather.rs +++ b/src/tools/miri/tests/fail/intrinsics/simd-gather.rs @@ -5,6 +5,7 @@ fn main() { unsafe { let vec: &[i8] = &[10, 11, 12, 13, 14, 15, 16, 17, 18]; let idxs = Simd::from_array([9, 3, 0, 17]); - let _result = Simd::gather_select_unchecked(&vec, Mask::splat(true), idxs, Simd::splat(0)); //~ERROR: pointer to 1 byte starting at offset 9 is out-of-bounds + let _result = Simd::gather_select_unchecked(&vec, Mask::splat(true), idxs, Simd::splat(0)); + //~^ERROR: expected a pointer to 1 byte of memory } } diff --git a/src/tools/miri/tests/fail/intrinsics/simd-gather.stderr b/src/tools/miri/tests/fail/intrinsics/simd-gather.stderr index d111644eec827..bc8d0b041d321 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-gather.stderr +++ b/src/tools/miri/tests/fail/intrinsics/simd-gather.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: ALLOC has size 9, so pointer to 1 byte starting at offset 9 is out-of-bounds +error: Undefined Behavior: memory access failed: expected a pointer to 1 byte of memory, but got ALLOC+0x9 which is at or beyond the end of the allocation of size 9 bytes --> $DIR/simd-gather.rs:LL:CC | LL | let _result = Simd::gather_select_unchecked(&vec, Mask::splat(true), idxs, Simd::splat(0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC has size 9, so pointer to 1 byte starting at offset 9 is out-of-bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 1 byte of memory, but got ALLOC+0x9 which is at or beyond the end of the allocation of size 9 bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/intrinsics/simd-scatter.rs b/src/tools/miri/tests/fail/intrinsics/simd-scatter.rs index 98b6749c584f9..bb8c9dbe4c7a8 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-scatter.rs +++ b/src/tools/miri/tests/fail/intrinsics/simd-scatter.rs @@ -6,7 +6,7 @@ fn main() { let mut vec: Vec = vec![10, 11, 12, 13, 14, 15, 16, 17, 18]; let idxs = Simd::from_array([9, 3, 0, 17]); Simd::from_array([-27, 82, -41, 124]).scatter_select_unchecked( - //~^ERROR: pointer to 1 byte starting at offset 9 is out-of-bounds + //~^ERROR: expected a pointer to 1 byte of memory &mut vec, Mask::splat(true), idxs, diff --git a/src/tools/miri/tests/fail/intrinsics/simd-scatter.stderr b/src/tools/miri/tests/fail/intrinsics/simd-scatter.stderr index 8b517b6e97252..aae77edcb6bd7 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-scatter.stderr +++ b/src/tools/miri/tests/fail/intrinsics/simd-scatter.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: memory access failed: ALLOC has size 9, so pointer to 1 byte starting at offset 9 is out-of-bounds +error: Undefined Behavior: memory access failed: expected a pointer to 1 byte of memory, but got ALLOC+0x9 which is at or beyond the end of the allocation of size 9 bytes --> $DIR/simd-scatter.rs:LL:CC | LL | / Simd::from_array([-27, 82, -41, 124]).scatter_select_unchecked( @@ -7,7 +7,7 @@ LL | | &mut vec, LL | | Mask::splat(true), LL | | idxs, LL | | ); - | |_________^ memory access failed: ALLOC has size 9, so pointer to 1 byte starting at offset 9 is out-of-bounds + | |_________^ memory access failed: expected a pointer to 1 byte of memory, but got ALLOC+0x9 which is at or beyond the end of the allocation of size 9 bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/provenance/pointer_partial_overwrite.stderr b/src/tools/miri/tests/fail/provenance/pointer_partial_overwrite.stderr index 50bff22f76678..1ca35be8cb2bd 100644 --- a/src/tools/miri/tests/fail/provenance/pointer_partial_overwrite.stderr +++ b/src/tools/miri/tests/fail/provenance/pointer_partial_overwrite.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: $HEX[noalloc] is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/pointer_partial_overwrite.rs:LL:CC | LL | let x = *p; - | ^^ memory access failed: $HEX[noalloc] is a dangling pointer (it has no provenance) + | ^^ memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/provenance/provenance_transmute.stderr b/src/tools/miri/tests/fail/provenance/provenance_transmute.stderr index 6b1c2941c075c..8a1d39effbd19 100644 --- a/src/tools/miri/tests/fail/provenance/provenance_transmute.stderr +++ b/src/tools/miri/tests/fail/provenance/provenance_transmute.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: $HEX[noalloc] is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/provenance_transmute.rs:LL:CC | LL | let _val = *left_ptr; - | ^^^^^^^^^ memory access failed: $HEX[noalloc] is a dangling pointer (it has no provenance) + | ^^^^^^^^^ memory access failed: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/provenance/ptr_int_unexposed.stderr b/src/tools/miri/tests/fail/provenance/ptr_int_unexposed.stderr index 92ccec5027497..e21872244f60c 100644 --- a/src/tools/miri/tests/fail/provenance/ptr_int_unexposed.stderr +++ b/src/tools/miri/tests/fail/provenance/ptr_int_unexposed.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: $HEX[noalloc] is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/ptr_int_unexposed.rs:LL:CC | LL | assert_eq!(unsafe { *ptr }, 3); - | ^^^^ memory access failed: $HEX[noalloc] is a dangling pointer (it has no provenance) + | ^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/provenance/ptr_invalid.stderr b/src/tools/miri/tests/fail/provenance/ptr_invalid.stderr index 8b8033b0d1d91..bd0a9eb0d2910 100644 --- a/src/tools/miri/tests/fail/provenance/ptr_invalid.stderr +++ b/src/tools/miri/tests/fail/provenance/ptr_invalid.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: $HEX[noalloc] is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/ptr_invalid.rs:LL:CC | LL | let _val = unsafe { *xptr_invalid }; - | ^^^^^^^^^^^^^ memory access failed: $HEX[noalloc] is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/provenance/ptr_invalid_offset.stderr b/src/tools/miri/tests/fail/provenance/ptr_invalid_offset.stderr index 8ae140ee004cf..35e5c08300f98 100644 --- a/src/tools/miri/tests/fail/provenance/ptr_invalid_offset.stderr +++ b/src/tools/miri/tests/fail/provenance/ptr_invalid_offset.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer arithmetic: $HEX[noalloc] is a dangling pointer (it has no provenance) +error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/ptr_invalid_offset.rs:LL:CC | LL | let _ = unsafe { roundtrip.offset(1) }; - | ^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: $HEX[noalloc] is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/reading_half_a_pointer.stderr b/src/tools/miri/tests/fail/reading_half_a_pointer.stderr index 03f93510d09b3..cba8a9f84396e 100644 --- a/src/tools/miri/tests/fail/reading_half_a_pointer.stderr +++ b/src/tools/miri/tests/fail/reading_half_a_pointer.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: $HEX[noalloc] is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) --> $DIR/reading_half_a_pointer.rs:LL:CC | LL | let _val = *x; - | ^^ memory access failed: $HEX[noalloc] is a dangling pointer (it has no provenance) + | ^^ memory access failed: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.rs b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.rs index 843d0d11873d2..75f7aae9718d6 100644 --- a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.rs +++ b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.rs @@ -4,6 +4,6 @@ extern "Rust" { fn main() { unsafe { - miri_resolve_frame(std::ptr::null_mut(), 0); //~ ERROR: null pointer is a dangling pointer + miri_resolve_frame(std::ptr::null_mut(), 0); //~ ERROR: got a null pointer } } diff --git a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr index 04dbd657d200c..523c935762ffd 100644 --- a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr +++ b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance) +error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer --> $DIR/bad-backtrace-ptr.rs:LL:CC | LL | miri_resolve_frame(std::ptr::null_mut(), 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/zst_local_oob.rs b/src/tools/miri/tests/fail/zst_local_oob.rs index cc81481e4fa4c..ab48b7d330b37 100644 --- a/src/tools/miri/tests/fail/zst_local_oob.rs +++ b/src/tools/miri/tests/fail/zst_local_oob.rs @@ -1,5 +1,5 @@ fn main() { // make sure ZST locals cannot be accessed let x = &() as *const () as *const i8; - let _val = unsafe { *x }; //~ ERROR: out-of-bounds + let _val = unsafe { *x }; //~ ERROR: expected a pointer to 1 byte of memory } diff --git a/src/tools/miri/tests/fail/zst_local_oob.stderr b/src/tools/miri/tests/fail/zst_local_oob.stderr index ba1ccaa0a3c8d..39ac2c91437c6 100644 --- a/src/tools/miri/tests/fail/zst_local_oob.stderr +++ b/src/tools/miri/tests/fail/zst_local_oob.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: ALLOC has size 0, so pointer to 1 byte starting at offset 0 is out-of-bounds +error: Undefined Behavior: memory access failed: expected a pointer to 1 byte of memory, but got ALLOC which is at or beyond the end of the allocation of size 0 bytes --> $DIR/zst_local_oob.rs:LL:CC | LL | let _val = unsafe { *x }; - | ^^ memory access failed: ALLOC has size 0, so pointer to 1 byte starting at offset 0 is out-of-bounds + | ^^ memory access failed: expected a pointer to 1 byte of memory, but got ALLOC which is at or beyond the end of the allocation of size 0 bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/ui/const-ptr/forbidden_slices.stderr b/tests/ui/const-ptr/forbidden_slices.stderr index eb41a25c818a0..034e8bd185264 100644 --- a/tests/ui/const-ptr/forbidden_slices.stderr +++ b/tests/ui/const-ptr/forbidden_slices.stderr @@ -118,7 +118,7 @@ LL | pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) }; error[E0080]: could not evaluate static initializer --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | - = note: out-of-bounds pointer arithmetic: ALLOC10 has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds + = note: out-of-bounds pointer arithmetic: expected a pointer to 8 bytes of memory, but got ALLOC10 and there are only 4 bytes starting at that pointer | note: inside `std::ptr::const_ptr::::add` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -177,7 +177,7 @@ LL | pub static R7: &[u16] = unsafe { error[E0080]: could not evaluate static initializer --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | - = note: out-of-bounds pointer arithmetic: ALLOC11 has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds + = note: out-of-bounds pointer arithmetic: expected a pointer to 8 bytes of memory, but got ALLOC11+0x1 and there are only 7 bytes starting at that pointer | note: inside `std::ptr::const_ptr::::add` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL diff --git a/tests/ui/const-ptr/out_of_bounds_read.stderr b/tests/ui/const-ptr/out_of_bounds_read.stderr index 7634ba252100c..7f354963eb1fd 100644 --- a/tests/ui/const-ptr/out_of_bounds_read.stderr +++ b/tests/ui/const-ptr/out_of_bounds_read.stderr @@ -1,7 +1,7 @@ error[E0080]: evaluation of constant value failed --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL | - = note: memory access failed: ALLOC0 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds + = note: memory access failed: expected a pointer to 4 bytes of memory, but got ALLOC0+0x4 which is at or beyond the end of the allocation of size 4 bytes | note: inside `std::ptr::read::` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL @@ -14,7 +14,7 @@ LL | const _READ: u32 = unsafe { ptr::read(PAST_END_PTR) }; error[E0080]: evaluation of constant value failed --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL | - = note: memory access failed: ALLOC0 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds + = note: memory access failed: expected a pointer to 4 bytes of memory, but got ALLOC0+0x4 which is at or beyond the end of the allocation of size 4 bytes | note: inside `std::ptr::read::` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL @@ -29,7 +29,7 @@ LL | const _CONST_READ: u32 = unsafe { PAST_END_PTR.read() }; error[E0080]: evaluation of constant value failed --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL | - = note: memory access failed: ALLOC0 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds + = note: memory access failed: expected a pointer to 4 bytes of memory, but got ALLOC0+0x4 which is at or beyond the end of the allocation of size 4 bytes | note: inside `std::ptr::read::` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL diff --git a/tests/ui/consts/const-compare-bytes-ub.stderr b/tests/ui/consts/const-compare-bytes-ub.stderr index 9e49706c4c836..8a923779a5bb4 100644 --- a/tests/ui/consts/const-compare-bytes-ub.stderr +++ b/tests/ui/consts/const-compare-bytes-ub.stderr @@ -2,31 +2,31 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-compare-bytes-ub.rs:10:9 | LL | compare_bytes(0 as *const u8, 2 as *const u8, 1) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 1 byte of memory, but got a null pointer error[E0080]: evaluation of constant value failed --> $DIR/const-compare-bytes-ub.rs:14:9 | LL | compare_bytes(1 as *const u8, 0 as *const u8, 1) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: 0x1[noalloc] is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 1 byte of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) error[E0080]: evaluation of constant value failed --> $DIR/const-compare-bytes-ub.rs:18:9 | LL | compare_bytes(1 as *const u8, 2 as *const u8, 1) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: 0x1[noalloc] is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 1 byte of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) error[E0080]: evaluation of constant value failed --> $DIR/const-compare-bytes-ub.rs:22:9 | LL | compare_bytes([1, 2, 3].as_ptr(), [1, 2, 3, 4].as_ptr(), 4) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC0 has size 3, so pointer to 4 bytes starting at offset 0 is out-of-bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got ALLOC0 and there are only 3 bytes starting at that pointer error[E0080]: evaluation of constant value failed --> $DIR/const-compare-bytes-ub.rs:26:9 | LL | compare_bytes([1, 2, 3, 4].as_ptr(), [1, 2, 3].as_ptr(), 4) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC1 has size 3, so pointer to 4 bytes starting at offset 0 is out-of-bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got ALLOC1 and there are only 3 bytes starting at that pointer error[E0080]: evaluation of constant value failed --> $DIR/const-compare-bytes-ub.rs:30:9 diff --git a/tests/ui/consts/const-deref-ptr.stderr b/tests/ui/consts/const-deref-ptr.stderr index b102b4d17cca1..070685e0b9d93 100644 --- a/tests/ui/consts/const-deref-ptr.stderr +++ b/tests/ui/consts/const-deref-ptr.stderr @@ -2,7 +2,7 @@ error[E0080]: could not evaluate static initializer --> $DIR/const-deref-ptr.rs:4:29 | LL | static C: u64 = unsafe {*(0xdeadbeef as *const u64)}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: 0xdeadbeef[noalloc] is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 8 bytes of memory, but got 0xdeadbeef[noalloc] which is a dangling pointer (it has no provenance) error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/const_raw_ptr_ops2.stderr b/tests/ui/consts/const-eval/const_raw_ptr_ops2.stderr index e6cd25e42ff7d..b0c864652e55e 100644 --- a/tests/ui/consts/const-eval/const_raw_ptr_ops2.stderr +++ b/tests/ui/consts/const-eval/const_raw_ptr_ops2.stderr @@ -2,13 +2,13 @@ error[E0080]: evaluation of constant value failed --> $DIR/const_raw_ptr_ops2.rs:7:26 | LL | const Z2: i32 = unsafe { *(42 as *const i32) }; - | ^^^^^^^^^^^^^^^^^^^ memory access failed: 0x2a[noalloc] is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance) error[E0080]: evaluation of constant value failed --> $DIR/const_raw_ptr_ops2.rs:9:26 | LL | const Z3: i32 = unsafe { *(44 as *const i32) }; - | ^^^^^^^^^^^^^^^^^^^ memory access failed: 0x2c[noalloc] is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got 0x2c[noalloc] which is a dangling pointer (it has no provenance) error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/nonnull_as_ref_ub.stderr b/tests/ui/consts/const-eval/nonnull_as_ref_ub.stderr index b878c8d1b3761..bd6dafb936653 100644 --- a/tests/ui/consts/const-eval/nonnull_as_ref_ub.stderr +++ b/tests/ui/consts/const-eval/nonnull_as_ref_ub.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/nonnull_as_ref_ub.rs:4:29 | LL | const _: () = assert!(42 == *unsafe { NON_NULL.as_ref() }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: 0x1[noalloc] is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 1 byte of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr index d7d24f373ebc1..25f17f9c38a97 100644 --- a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr +++ b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr @@ -440,7 +440,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/raw-bytes.rs:196:62 | LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer error[E0080]: evaluation of constant value failed --> $DIR/raw-bytes.rs:199:65 diff --git a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr index 22679acda98b8..0fb9694895d8e 100644 --- a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr +++ b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr @@ -440,7 +440,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/raw-bytes.rs:196:62 | LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer error[E0080]: evaluation of constant value failed --> $DIR/raw-bytes.rs:199:65 diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.rs b/tests/ui/consts/const-eval/raw-pointer-ub.rs index 47105de453cb1..5aced5b1bd6d5 100644 --- a/tests/ui/consts/const-eval/raw-pointer-ub.rs +++ b/tests/ui/consts/const-eval/raw-pointer-ub.rs @@ -39,7 +39,7 @@ const OOB: () = unsafe { let mem = [0u32; 1]; let ptr = mem.as_ptr().cast::(); let _val = *ptr; //~ERROR: evaluation of constant value failed - //~^NOTE: size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds + //~^NOTE: expected a pointer to 8 bytes of memory }; fn main() {} diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.stderr b/tests/ui/consts/const-eval/raw-pointer-ub.stderr index cba06fdc639f5..5fce25701bdd1 100644 --- a/tests/ui/consts/const-eval/raw-pointer-ub.stderr +++ b/tests/ui/consts/const-eval/raw-pointer-ub.stderr @@ -35,7 +35,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/raw-pointer-ub.rs:41:16 | LL | let _val = *ptr; - | ^^^^ memory access failed: ALLOC0 has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds + | ^^^^ memory access failed: expected a pointer to 8 bytes of memory, but got ALLOC0 and there are only 4 bytes starting at that pointer error: aborting due to 5 previous errors diff --git a/tests/ui/consts/const-eval/ub-nonnull.stderr b/tests/ui/consts/const-eval/ub-nonnull.stderr index ab0fb2abdb309..fe3060dda17df 100644 --- a/tests/ui/consts/const-eval/ub-nonnull.stderr +++ b/tests/ui/consts/const-eval/ub-nonnull.stderr @@ -13,7 +13,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/ub-nonnull.rs:20:29 | LL | let out_of_bounds_ptr = &ptr[255]; - | ^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC1 has size 1, so pointer to 255 bytes starting at offset 0 is out-of-bounds + | ^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to 255 bytes of memory, but got ALLOC1 and there are only 1 bytes starting at that pointer error[E0080]: it is undefined behavior to use this value --> $DIR/ub-nonnull.rs:24:1 diff --git a/tests/ui/consts/const-eval/ub-wide-ptr.stderr b/tests/ui/consts/const-eval/ub-wide-ptr.stderr index 4fe744265dfb3..c29cc836fffdb 100644 --- a/tests/ui/consts/const-eval/ub-wide-ptr.stderr +++ b/tests/ui/consts/const-eval/ub-wide-ptr.stderr @@ -262,7 +262,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/ub-wide-ptr.rs:144:62 | LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer error[E0080]: evaluation of constant value failed --> $DIR/ub-wide-ptr.rs:147:65 @@ -274,7 +274,7 @@ error[E0080]: could not evaluate static initializer --> $DIR/ub-wide-ptr.rs:156:5 | LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer error[E0080]: could not evaluate static initializer --> $DIR/ub-wide-ptr.rs:161:5 diff --git a/tests/ui/consts/copy-intrinsic.rs b/tests/ui/consts/copy-intrinsic.rs index 4183dc0fcd6db..e3f43ce203754 100644 --- a/tests/ui/consts/copy-intrinsic.rs +++ b/tests/ui/consts/copy-intrinsic.rs @@ -27,7 +27,7 @@ const COPY_OOB_1: () = unsafe { copy_nonoverlapping(0x100 as *const i32, dangle, 0); // Non-zero-sized copy is not. copy_nonoverlapping(0x100 as *const i32, dangle, 1); //~ ERROR evaluation of constant value failed [E0080] - //~| 0x100[noalloc] is a dangling pointer + //~| got 0x100[noalloc] which is a dangling pointer }; const COPY_OOB_2: () = unsafe { let x = 0i32; @@ -36,7 +36,7 @@ const COPY_OOB_2: () = unsafe { copy_nonoverlapping(dangle, 0x100 as *mut i32, 0); // Non-zero-sized copy is not. copy_nonoverlapping(dangle, 0x100 as *mut i32, 1); //~ ERROR evaluation of constant value failed [E0080] - //~| offset 40 is out-of-bounds + //~| +0x28 which is at or beyond the end of the allocation }; const COPY_SIZE_OVERFLOW: () = unsafe { diff --git a/tests/ui/consts/copy-intrinsic.stderr b/tests/ui/consts/copy-intrinsic.stderr index d34e61cd96273..2dbb471131ecf 100644 --- a/tests/ui/consts/copy-intrinsic.stderr +++ b/tests/ui/consts/copy-intrinsic.stderr @@ -2,13 +2,13 @@ error[E0080]: evaluation of constant value failed --> $DIR/copy-intrinsic.rs:29:5 | LL | copy_nonoverlapping(0x100 as *const i32, dangle, 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: 0x100[noalloc] is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got 0x100[noalloc] which is a dangling pointer (it has no provenance) error[E0080]: evaluation of constant value failed --> $DIR/copy-intrinsic.rs:38:5 | LL | copy_nonoverlapping(dangle, 0x100 as *mut i32, 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC0 has size 4, so pointer to 4 bytes starting at offset 40 is out-of-bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got ALLOC0+0x28 which is at or beyond the end of the allocation of size 4 bytes error[E0080]: evaluation of constant value failed --> $DIR/copy-intrinsic.rs:45:5 diff --git a/tests/ui/consts/offset_from_ub.rs b/tests/ui/consts/offset_from_ub.rs index 95b3118f1570a..66bb056ceb049 100644 --- a/tests/ui/consts/offset_from_ub.rs +++ b/tests/ui/consts/offset_from_ub.rs @@ -1,3 +1,4 @@ +//@ normalize-stderr-test: "to \d+ bytes of memory" -> "to $$BYTES bytes of memory" #![feature(const_ptr_sub_ptr)] #![feature(core_intrinsics)] @@ -45,7 +46,7 @@ const OUT_OF_BOUNDS_1: isize = { let end_ptr = (start_ptr).wrapping_add(length); // First ptr is out of bounds unsafe { ptr_offset_from(end_ptr, start_ptr) } //~ERROR evaluation of constant value failed - //~| pointer to 10 bytes starting at offset 0 is out-of-bounds + //~| expected a pointer to 10 bytes of memory }; const OUT_OF_BOUNDS_2: isize = { @@ -54,7 +55,7 @@ const OUT_OF_BOUNDS_2: isize = { let end_ptr = (start_ptr).wrapping_add(length); // Second ptr is out of bounds unsafe { ptr_offset_from(start_ptr, end_ptr) } //~ERROR evaluation of constant value failed - //~| pointer to 10 bytes starting at offset 0 is out-of-bounds + //~| expected a pointer to 10 bytes of memory }; pub const DIFFERENT_ALLOC_UNSIGNED: usize = { diff --git a/tests/ui/consts/offset_from_ub.stderr b/tests/ui/consts/offset_from_ub.stderr index 0a860f42c649c..f2f27735630fe 100644 --- a/tests/ui/consts/offset_from_ub.stderr +++ b/tests/ui/consts/offset_from_ub.stderr @@ -1,5 +1,5 @@ error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:18:27 + --> $DIR/offset_from_ub.rs:19:27 | LL | let offset = unsafe { ptr_offset_from(field_ptr, base_ptr) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on pointers into different allocations @@ -12,67 +12,67 @@ error[E0080]: evaluation of constant value failed note: inside `std::ptr::const_ptr::::offset_from` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `NOT_PTR` - --> $DIR/offset_from_ub.rs:24:14 + --> $DIR/offset_from_ub.rs:25:14 | LL | unsafe { (42 as *const u8).offset_from(&5u8) as usize } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:31:14 + --> $DIR/offset_from_ub.rs:32:14 | LL | unsafe { ptr_offset_from(field_ptr, base_ptr as *const u16) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exact_div: 1_isize cannot be divided by 2_isize without remainder error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:38:14 + --> $DIR/offset_from_ub.rs:39:14 | LL | unsafe { ptr_offset_from(ptr2, ptr1) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from`: 0x8[noalloc] is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from`: expected a pointer to $BYTES bytes of memory, but got 0x8[noalloc] which is a dangling pointer (it has no provenance) error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:47:14 + --> $DIR/offset_from_ub.rs:48:14 | LL | unsafe { ptr_offset_from(end_ptr, start_ptr) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from`: ALLOC0 has size 4, so pointer to 10 bytes starting at offset 0 is out-of-bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from`: expected a pointer to $BYTES bytes of memory, but got ALLOC0 and there are only 4 bytes starting at that pointer error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:56:14 + --> $DIR/offset_from_ub.rs:57:14 | LL | unsafe { ptr_offset_from(start_ptr, end_ptr) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from`: ALLOC1 has size 4, so pointer to 10 bytes starting at offset 0 is out-of-bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from`: expected a pointer to $BYTES bytes of memory, but got ALLOC1 and there are only 4 bytes starting at that pointer error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:65:14 + --> $DIR/offset_from_ub.rs:66:14 | LL | unsafe { ptr_offset_from_unsigned(field_ptr, base_ptr) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called on pointers into different allocations error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:72:14 + --> $DIR/offset_from_ub.rs:73:14 | LL | unsafe { ptr_offset_from(ptr2, ptr1) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far ahead of second error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:78:14 + --> $DIR/offset_from_ub.rs:79:14 | LL | unsafe { ptr_offset_from(ptr1, ptr2) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far before second error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:86:14 + --> $DIR/offset_from_ub.rs:87:14 | LL | unsafe { ptr_offset_from(ptr1, ptr2) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far before second error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:93:14 + --> $DIR/offset_from_ub.rs:94:14 | LL | unsafe { ptr_offset_from_unsigned(p, p.add(2) ) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer has smaller offset than second: 0 < 8 error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:100:14 + --> $DIR/offset_from_ub.rs:101:14 | LL | unsafe { ptr_offset_from_unsigned(ptr2, ptr1) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer is too far ahead of second @@ -80,12 +80,12 @@ LL | unsafe { ptr_offset_from_unsigned(ptr2, ptr1) } error[E0080]: evaluation of constant value failed --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | - = note: out-of-bounds `offset_from`: null pointer is a dangling pointer (it has no provenance) + = note: out-of-bounds `offset_from`: expected a pointer to $BYTES bytes of memory, but got a null pointer | note: inside `std::ptr::const_ptr::::offset_from` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `OFFSET_VERY_FAR1` - --> $DIR/offset_from_ub.rs:109:14 + --> $DIR/offset_from_ub.rs:110:14 | LL | unsafe { ptr2.offset_from(ptr1) } | ^^^^^^^^^^^^^^^^^^^^^^ @@ -98,7 +98,7 @@ error[E0080]: evaluation of constant value failed note: inside `std::ptr::const_ptr::::offset_from` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `OFFSET_VERY_FAR2` - --> $DIR/offset_from_ub.rs:115:14 + --> $DIR/offset_from_ub.rs:116:14 | LL | unsafe { ptr1.offset_from(ptr2.wrapping_offset(1)) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/consts/offset_ub.rs b/tests/ui/consts/offset_ub.rs index 9a8f756749b70..b239b91e11cf6 100644 --- a/tests/ui/consts/offset_ub.rs +++ b/tests/ui/consts/offset_ub.rs @@ -2,6 +2,7 @@ use std::ptr; //@ normalize-stderr-test: "0xf+" -> "0xf..f" //@ normalize-stderr-test: "0x7f+" -> "0x7f..f" +//@ normalize-stderr-test: "to \d+ bytes of memory" -> "to $$BYTES bytes of memory" pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) }; //~NOTE diff --git a/tests/ui/consts/offset_ub.stderr b/tests/ui/consts/offset_ub.stderr index 89371f06d9d65..b42d9482f8a01 100644 --- a/tests/ui/consts/offset_ub.stderr +++ b/tests/ui/consts/offset_ub.stderr @@ -6,7 +6,7 @@ error[E0080]: evaluation of constant value failed note: inside `std::ptr::const_ptr::::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `BEFORE_START` - --> $DIR/offset_ub.rs:7:46 + --> $DIR/offset_ub.rs:8:46 | LL | pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -14,12 +14,12 @@ LL | pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) error[E0080]: evaluation of constant value failed --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | - = note: out-of-bounds pointer arithmetic: ALLOC0 has size 1, so pointer to 2 bytes starting at offset 0 is out-of-bounds + = note: out-of-bounds pointer arithmetic: expected a pointer to $BYTES bytes of memory, but got ALLOC0 and there are only 1 bytes starting at that pointer | note: inside `std::ptr::const_ptr::::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `AFTER_END` - --> $DIR/offset_ub.rs:8:43 + --> $DIR/offset_ub.rs:9:43 | LL | pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -27,12 +27,12 @@ LL | pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) }; error[E0080]: evaluation of constant value failed --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | - = note: out-of-bounds pointer arithmetic: ALLOC1 has size 100, so pointer to 101 bytes starting at offset 0 is out-of-bounds + = note: out-of-bounds pointer arithmetic: expected a pointer to $BYTES bytes of memory, but got ALLOC1 and there are only 100 bytes starting at that pointer | note: inside `std::ptr::const_ptr::::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `AFTER_ARRAY` - --> $DIR/offset_ub.rs:9:45 + --> $DIR/offset_ub.rs:10:45 | LL | pub const AFTER_ARRAY: *const u8 = unsafe { [0u8; 100].as_ptr().offset(101) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -45,7 +45,7 @@ error[E0080]: evaluation of constant value failed note: inside `std::ptr::const_ptr::::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `OVERFLOW` - --> $DIR/offset_ub.rs:11:43 + --> $DIR/offset_ub.rs:12:43 | LL | pub const OVERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MAX) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -58,7 +58,7 @@ error[E0080]: evaluation of constant value failed note: inside `std::ptr::const_ptr::::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `UNDERFLOW` - --> $DIR/offset_ub.rs:12:44 + --> $DIR/offset_ub.rs:13:44 | LL | pub const UNDERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MIN) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -71,7 +71,7 @@ error[E0080]: evaluation of constant value failed note: inside `std::ptr::const_ptr::::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `OVERFLOW_ADDRESS_SPACE` - --> $DIR/offset_ub.rs:13:56 + --> $DIR/offset_ub.rs:14:56 | LL | pub const OVERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (usize::MAX as *const u8).offset(2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -84,7 +84,7 @@ error[E0080]: evaluation of constant value failed note: inside `std::ptr::const_ptr::::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `UNDERFLOW_ADDRESS_SPACE` - --> $DIR/offset_ub.rs:14:57 + --> $DIR/offset_ub.rs:15:57 | LL | pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).offset(-2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -92,12 +92,12 @@ LL | pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).of error[E0080]: evaluation of constant value failed --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | - = note: out-of-bounds pointer arithmetic: ALLOC2 has size 1, so pointer to 2 bytes starting at offset -4 is out-of-bounds + = note: out-of-bounds pointer arithmetic: expected a pointer to $BYTES bytes of memory, but got ALLOC2-0x4 which points to before the beginning of the allocation | note: inside `std::ptr::const_ptr::::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `NEGATIVE_OFFSET` - --> $DIR/offset_ub.rs:15:49 + --> $DIR/offset_ub.rs:16:49 | LL | pub const NEGATIVE_OFFSET: *const u8 = unsafe { [0u8; 1].as_ptr().wrapping_offset(-2).offset(-2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -105,12 +105,12 @@ LL | pub const NEGATIVE_OFFSET: *const u8 = unsafe { [0u8; 1].as_ptr().wrapping_ error[E0080]: evaluation of constant value failed --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | - = note: out-of-bounds pointer arithmetic: ALLOC3 has size 0, so pointer to 1 byte starting at offset 0 is out-of-bounds + = note: out-of-bounds pointer arithmetic: expected a pointer to 1 byte of memory, but got ALLOC3 which is at or beyond the end of the allocation of size 0 bytes | note: inside `std::ptr::const_ptr::::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `ZERO_SIZED_ALLOC` - --> $DIR/offset_ub.rs:17:50 + --> $DIR/offset_ub.rs:18:50 | LL | pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -118,12 +118,12 @@ LL | pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1 error[E0080]: evaluation of constant value failed --> $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL | - = note: out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance) + = note: out-of-bounds pointer arithmetic: expected a pointer to $BYTES bytes of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) | note: inside `std::ptr::mut_ptr::::offset` --> $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL note: inside `DANGLING` - --> $DIR/offset_ub.rs:18:42 + --> $DIR/offset_ub.rs:19:42 | LL | pub const DANGLING: *const u8 = unsafe { ptr::NonNull::::dangling().as_ptr().offset(4) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -131,12 +131,12 @@ LL | pub const DANGLING: *const u8 = unsafe { ptr::NonNull::::dangling().as_ error[E0080]: evaluation of constant value failed --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | - = note: out-of-bounds pointer arithmetic: 0x7f..f[noalloc] is a dangling pointer (it has no provenance) + = note: out-of-bounds pointer arithmetic: expected a pointer to $BYTES bytes of memory, but got 0x7f..f[noalloc] which is a dangling pointer (it has no provenance) | note: inside `std::ptr::const_ptr::::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `UNDERFLOW_ABS` - --> $DIR/offset_ub.rs:21:47 + --> $DIR/offset_ub.rs:22:47 | LL | pub const UNDERFLOW_ABS: *const u8 = unsafe { (usize::MAX as *const u8).offset(isize::MIN) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/error-codes/E0396-fixed.stderr b/tests/ui/error-codes/E0396-fixed.stderr index 2f8ea7993f723..c14f4948095de 100644 --- a/tests/ui/error-codes/E0396-fixed.stderr +++ b/tests/ui/error-codes/E0396-fixed.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/E0396-fixed.rs:5:28 | LL | const VALUE: u8 = unsafe { *REG_ADDR }; - | ^^^^^^^^^ memory access failed: 0x5f3759df[noalloc] is a dangling pointer (it has no provenance) + | ^^^^^^^^^ memory access failed: expected a pointer to 1 byte of memory, but got 0x5f3759df[noalloc] which is a dangling pointer (it has no provenance) error: aborting due to 1 previous error From e1fc4a997ddac2b949ef6bb4037f1fb196c44f08 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 28 Jul 2024 15:12:14 +1000 Subject: [PATCH 24/33] Don't store `thir::Pat` in error structs In several cases this avoids the need to clone the underlying pattern, and then print the clone later. --- compiler/rustc_middle/src/thir.rs | 7 --- compiler/rustc_mir_build/src/errors.rs | 2 +- compiler/rustc_pattern_analysis/src/errors.rs | 53 +++++++++---------- compiler/rustc_pattern_analysis/src/rustc.rs | 10 ++-- 4 files changed, 32 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index b80d00719ee5e..1300a06f37510 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -9,7 +9,6 @@ //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/thir.html use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; -use rustc_errors::{DiagArgValue, IntoDiagArg}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::{BindingMode, ByRef, HirId, MatchSource, RangeEnd}; @@ -702,12 +701,6 @@ impl<'tcx> Pat<'tcx> { } } -impl<'tcx> IntoDiagArg for Pat<'tcx> { - fn into_diag_arg(self) -> DiagArgValue { - format!("{self}").into_diag_arg() - } -} - #[derive(Clone, Debug, HashStable, TypeVisitable)] pub struct Ascription<'tcx> { pub annotation: CanonicalUserTypeAnnotation<'tcx>, diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index bdc4b0ea97d18..2e508829fbe3c 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -856,7 +856,7 @@ pub(crate) struct PatternNotCovered<'s, 'tcx> { pub(crate) span: Span, pub(crate) origin: &'s str, #[subdiagnostic] - pub(crate) uncovered: Uncovered<'tcx>, + pub(crate) uncovered: Uncovered, #[subdiagnostic] pub(crate) inform: Option, #[subdiagnostic] diff --git a/compiler/rustc_pattern_analysis/src/errors.rs b/compiler/rustc_pattern_analysis/src/errors.rs index 27f227e6d9c11..bad41ac77f098 100644 --- a/compiler/rustc_pattern_analysis/src/errors.rs +++ b/compiler/rustc_pattern_analysis/src/errors.rs @@ -1,6 +1,5 @@ use rustc_errors::{Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic}; use rustc_macros::{LintDiagnostic, Subdiagnostic}; -use rustc_middle::thir::Pat; use rustc_middle::ty::Ty; use rustc_span::Span; @@ -8,18 +7,18 @@ use crate::rustc::{RustcPatCtxt, WitnessPat}; #[derive(Subdiagnostic)] #[label(pattern_analysis_uncovered)] -pub struct Uncovered<'tcx> { +pub struct Uncovered { #[primary_span] span: Span, count: usize, - witness_1: Pat<'tcx>, - witness_2: Pat<'tcx>, - witness_3: Pat<'tcx>, + witness_1: String, // a printed pattern + witness_2: String, // a printed pattern + witness_3: String, // a printed pattern remainder: usize, } -impl<'tcx> Uncovered<'tcx> { - pub fn new<'p>( +impl Uncovered { + pub fn new<'p, 'tcx>( span: Span, cx: &RustcPatCtxt<'p, 'tcx>, witnesses: Vec>, @@ -27,19 +26,19 @@ impl<'tcx> Uncovered<'tcx> { where 'tcx: 'p, { - let witness_1 = cx.hoist_witness_pat(witnesses.get(0).unwrap()); + let witness_1 = cx.hoist_witness_pat(witnesses.get(0).unwrap()).to_string(); Self { span, count: witnesses.len(), // Substitute dummy values if witnesses is smaller than 3. These will never be read. witness_2: witnesses .get(1) - .map(|w| cx.hoist_witness_pat(w)) - .unwrap_or_else(|| witness_1.clone()), + .map(|w| cx.hoist_witness_pat(w).to_string()) + .unwrap_or_default(), witness_3: witnesses .get(2) - .map(|w| cx.hoist_witness_pat(w)) - .unwrap_or_else(|| witness_1.clone()), + .map(|w| cx.hoist_witness_pat(w).to_string()) + .unwrap_or_default(), witness_1, remainder: witnesses.len().saturating_sub(3), } @@ -49,19 +48,19 @@ impl<'tcx> Uncovered<'tcx> { #[derive(LintDiagnostic)] #[diag(pattern_analysis_overlapping_range_endpoints)] #[note] -pub struct OverlappingRangeEndpoints<'tcx> { +pub struct OverlappingRangeEndpoints { #[label] pub range: Span, #[subdiagnostic] - pub overlap: Vec>, + pub overlap: Vec, } -pub struct Overlap<'tcx> { +pub struct Overlap { pub span: Span, - pub range: Pat<'tcx>, + pub range: String, // a printed pattern } -impl<'tcx> Subdiagnostic for Overlap<'tcx> { +impl Subdiagnostic for Overlap { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, @@ -78,38 +77,38 @@ impl<'tcx> Subdiagnostic for Overlap<'tcx> { #[derive(LintDiagnostic)] #[diag(pattern_analysis_excluside_range_missing_max)] -pub struct ExclusiveRangeMissingMax<'tcx> { +pub struct ExclusiveRangeMissingMax { #[label] #[suggestion(code = "{suggestion}", applicability = "maybe-incorrect")] /// This is an exclusive range that looks like `lo..max` (i.e. doesn't match `max`). pub first_range: Span, /// Suggest `lo..=max` instead. pub suggestion: String, - pub max: Pat<'tcx>, + pub max: String, // a printed pattern } #[derive(LintDiagnostic)] #[diag(pattern_analysis_excluside_range_missing_gap)] -pub struct ExclusiveRangeMissingGap<'tcx> { +pub struct ExclusiveRangeMissingGap { #[label] #[suggestion(code = "{suggestion}", applicability = "maybe-incorrect")] /// This is an exclusive range that looks like `lo..gap` (i.e. doesn't match `gap`). pub first_range: Span, - pub gap: Pat<'tcx>, + pub gap: String, // a printed pattern /// Suggest `lo..=gap` instead. pub suggestion: String, #[subdiagnostic] /// All these ranges skipped over `gap` which we think is probably a mistake. - pub gap_with: Vec>, + pub gap_with: Vec, } -pub struct GappedRange<'tcx> { +pub struct GappedRange { pub span: Span, - pub gap: Pat<'tcx>, - pub first_range: Pat<'tcx>, + pub gap: String, // a printed pattern + pub first_range: String, // a printed pattern } -impl<'tcx> Subdiagnostic for GappedRange<'tcx> { +impl Subdiagnostic for GappedRange { fn add_to_diag_with>( self, diag: &mut Diag<'_, G>, @@ -134,7 +133,7 @@ impl<'tcx> Subdiagnostic for GappedRange<'tcx> { pub(crate) struct NonExhaustiveOmittedPattern<'tcx> { pub scrut_ty: Ty<'tcx>, #[subdiagnostic] - pub uncovered: Uncovered<'tcx>, + pub uncovered: Uncovered, } #[derive(LintDiagnostic)] diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 910dd4c6c1a84..ceddafa2f4ceb 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -966,7 +966,7 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> { let overlaps: Vec<_> = overlaps_with .iter() .map(|pat| pat.data().span) - .map(|span| errors::Overlap { range: overlap_as_pat.clone(), span }) + .map(|span| errors::Overlap { range: overlap_as_pat.to_string(), span }) .collect(); let pat_span = pat.data().span; self.tcx.emit_node_span_lint( @@ -1014,7 +1014,7 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> { // Point at this range. first_range: thir_pat.span, // That's the gap that isn't covered. - max: gap_as_pat.clone(), + max: gap_as_pat.to_string(), // Suggest `lo..=max` instead. suggestion: suggested_range.to_string(), }, @@ -1028,7 +1028,7 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> { // Point at this range. first_range: thir_pat.span, // That's the gap that isn't covered. - gap: gap_as_pat.clone(), + gap: gap_as_pat.to_string(), // Suggest `lo..=gap` instead. suggestion: suggested_range.to_string(), // All these ranges skipped over `gap` which we think is probably a @@ -1037,8 +1037,8 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> { .iter() .map(|pat| errors::GappedRange { span: pat.data().span, - gap: gap_as_pat.clone(), - first_range: thir_pat.clone(), + gap: gap_as_pat.to_string(), + first_range: thir_pat.to_string(), }) .collect(), }, From cf87203f483751e0f6daa74b9d129c04feb48355 Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Sun, 28 Jul 2024 16:37:58 +0200 Subject: [PATCH 25/33] Remove spurious backticks detected by `rustdoc::unescaped_backticks` There are only 3 cases across the crates rendered in the website (`core`, `alloc`, `std`, `proc_macro` and `test`), and they are all in `core`. Clean them up, so that the lint can be enabled in the next commit. Signed-off-by: Miguel Ojeda --- library/core/src/ops/deref.rs | 2 +- library/core/src/ptr/mod.rs | 2 +- library/core/src/slice/mod.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs index 9849410d484ca..f0d2c761ef35b 100644 --- a/library/core/src/ops/deref.rs +++ b/library/core/src/ops/deref.rs @@ -282,7 +282,7 @@ impl DerefMut for &mut T { /// FIXME(deref_patterns): The precise semantics are undecided; the rough idea is that /// successive calls to `deref`/`deref_mut` without intermediate mutation should be /// idempotent, in the sense that they return the same value as far as pattern-matching -/// is concerned. Calls to `deref`/`deref_mut`` must leave the pointer itself likewise +/// is concerned. Calls to `deref`/`deref_mut` must leave the pointer itself likewise /// unchanged. #[unstable(feature = "deref_pure_trait", issue = "87121")] #[lang = "deref_pure"] diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index da6b541a98700..2566beeadac5d 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -786,7 +786,7 @@ where /// /// The caller must also ensure that the memory the pointer (non-transitively) points to is never /// written to (except inside an `UnsafeCell`) using this pointer or any pointer derived from it. If -/// you need to mutate the pointee, use [`from_mut`]`. Specifically, to turn a mutable reference `m: +/// you need to mutate the pointee, use [`from_mut`]. Specifically, to turn a mutable reference `m: /// &mut T` into `*const T`, prefer `from_mut(m).cast_const()` to obtain a pointer that can later be /// used for mutation. /// diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 5f75e1944122d..067daa6a0d09c 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -3452,8 +3452,8 @@ impl [T] { /// elements of the slice move to the end while the last `k` elements move /// to the front. /// - /// After calling `rotate_right`, the element previously at index `self.len() - /// - k` will become the first element in the slice. + /// After calling `rotate_right`, the element previously at index + /// `self.len() - k` will become the first element in the slice. /// /// # Panics /// From dc815df1e1dc8c37956e41274c3276d053c271da Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Sun, 28 Jul 2024 16:37:58 +0200 Subject: [PATCH 26/33] Warn on `rustdoc::unescaped_backticks` for `core/alloc/std/test/proc_macro` They are all clean now, so enable the lint to keep them clean going forward. Signed-off-by: Miguel Ojeda --- library/alloc/src/lib.rs | 1 + library/core/src/lib.rs | 1 + library/proc_macro/src/lib.rs | 1 + library/std/src/lib.rs | 1 + library/test/src/lib.rs | 1 + 5 files changed, 5 insertions(+) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 3b039786eb5e7..6c58594605004 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -86,6 +86,7 @@ #![warn(multiple_supertrait_upcastable)] #![allow(internal_features)] #![allow(rustdoc::redundant_explicit_links)] +#![warn(rustdoc::unescaped_backticks)] #![deny(ffi_unwind_calls)] // // Library features: diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index e8f08db94164d..a3eca34a35cfc 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -103,6 +103,7 @@ #![deny(ffi_unwind_calls)] // Do not check link redundancy on bootstraping phase #![allow(rustdoc::redundant_explicit_links)] +#![warn(rustdoc::unescaped_backticks)] // // Library features: // tidy-alphabetical-start diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 57247359fbf29..10dcaa8cd3aaf 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -37,6 +37,7 @@ #![recursion_limit = "256"] #![allow(internal_features)] #![deny(ffi_unwind_calls)] +#![warn(rustdoc::unescaped_backticks)] #[unstable(feature = "proc_macro_internals", issue = "27812")] #[doc(hidden)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 353fd8d2de8c0..7240605bfd654 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -254,6 +254,7 @@ #![deny(fuzzy_provenance_casts)] #![deny(unsafe_op_in_unsafe_fn)] #![allow(rustdoc::redundant_explicit_links)] +#![warn(rustdoc::unescaped_backticks)] // Ensure that std can be linked against panic_abort despite compiled with `-C panic=unwind` #![deny(ffi_unwind_calls)] // std may use features in a platform-specific way diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 71cb796b93705..db87d923de0e5 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -24,6 +24,7 @@ #![feature(panic_can_unwind)] #![feature(test)] #![allow(internal_features)] +#![warn(rustdoc::unescaped_backticks)] pub use self::bench::{black_box, Bencher}; pub use self::console::run_tests_console; From 41cf8374a640fca0f5d5b97c345aa4c3c0df9c25 Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Sun, 28 Jul 2024 22:30:01 +0200 Subject: [PATCH 27/33] CI: move RFL job forward to v6.11-rc1 The tag has been released today, and since the original hash we had in the Rust CI (which was ~v6.10-rc1), we have accumulated a fair amount of changes and new code. In particular, v6.11-rc1 is the first Linux tag where the kernel is supporting an actual minimum Rust version (1.78.0), rather than a single version. Signed-off-by: Miguel Ojeda --- src/ci/docker/scripts/rfl-build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/docker/scripts/rfl-build.sh b/src/ci/docker/scripts/rfl-build.sh index da7b029ca7329..3acc09e0b9b1a 100755 --- a/src/ci/docker/scripts/rfl-build.sh +++ b/src/ci/docker/scripts/rfl-build.sh @@ -2,7 +2,7 @@ set -euo pipefail -LINUX_VERSION=c13320499ba0efd93174ef6462ae8a7a2933f6e7 +LINUX_VERSION=v6.11-rc1 # Build rustc, rustdoc and cargo ../x.py build --stage 1 library rustdoc From db05b0fd343e8204460b0e1f3e261cc4ae940e0a Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 28 Jul 2024 15:14:26 +1000 Subject: [PATCH 28/33] Encapsulate the printing of `WitnessPat` This hides the fact that we print `WitnessPat` by converting it to `thir::Pat` and then printing that. --- .../src/thir/pattern/check_match.rs | 8 ++++---- compiler/rustc_pattern_analysis/src/errors.rs | 12 +++--------- compiler/rustc_pattern_analysis/src/rustc.rs | 14 +++++++++++--- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 5e904057e732c..0632911671e12 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -1077,7 +1077,7 @@ fn report_non_exhaustive_match<'p, 'tcx>( let suggested_arm = if suggest_the_witnesses { let pattern = witnesses .iter() - .map(|witness| cx.hoist_witness_pat(witness).to_string()) + .map(|witness| cx.print_witness_pat(witness)) .collect::>() .join(" | "); if witnesses.iter().all(|p| p.is_never_pattern()) && cx.tcx.features().never_patterns { @@ -1195,13 +1195,13 @@ fn joined_uncovered_patterns<'p, 'tcx>( witnesses: &[WitnessPat<'p, 'tcx>], ) -> String { const LIMIT: usize = 3; - let pat_to_str = |pat: &WitnessPat<'p, 'tcx>| cx.hoist_witness_pat(pat).to_string(); + let pat_to_str = |pat: &WitnessPat<'p, 'tcx>| cx.print_witness_pat(pat); match witnesses { [] => bug!(), - [witness] => format!("`{}`", cx.hoist_witness_pat(witness)), + [witness] => format!("`{}`", cx.print_witness_pat(witness)), [head @ .., tail] if head.len() < LIMIT => { let head: Vec<_> = head.iter().map(pat_to_str).collect(); - format!("`{}` and `{}`", head.join("`, `"), cx.hoist_witness_pat(tail)) + format!("`{}` and `{}`", head.join("`, `"), cx.print_witness_pat(tail)) } _ => { let (head, tail) = witnesses.split_at(LIMIT); diff --git a/compiler/rustc_pattern_analysis/src/errors.rs b/compiler/rustc_pattern_analysis/src/errors.rs index bad41ac77f098..1f7852e5190d2 100644 --- a/compiler/rustc_pattern_analysis/src/errors.rs +++ b/compiler/rustc_pattern_analysis/src/errors.rs @@ -26,19 +26,13 @@ impl Uncovered { where 'tcx: 'p, { - let witness_1 = cx.hoist_witness_pat(witnesses.get(0).unwrap()).to_string(); + let witness_1 = cx.print_witness_pat(witnesses.get(0).unwrap()); Self { span, count: witnesses.len(), // Substitute dummy values if witnesses is smaller than 3. These will never be read. - witness_2: witnesses - .get(1) - .map(|w| cx.hoist_witness_pat(w).to_string()) - .unwrap_or_default(), - witness_3: witnesses - .get(2) - .map(|w| cx.hoist_witness_pat(w).to_string()) - .unwrap_or_default(), + witness_2: witnesses.get(1).map(|w| cx.print_witness_pat(w)).unwrap_or_default(), + witness_3: witnesses.get(2).map(|w| cx.print_witness_pat(w)).unwrap_or_default(), witness_1, remainder: witnesses.len().saturating_sub(3), } diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index ceddafa2f4ceb..b04c21a384c8c 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -744,7 +744,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { /// Note: it is possible to get `isize/usize::MAX+1` here, as explained in the doc for /// [`IntRange::split`]. This cannot be represented as a `Const`, so we represent it with /// `PosInfinity`. - pub(crate) fn hoist_pat_range_bdy( + fn hoist_pat_range_bdy( &self, miint: MaybeInfiniteInt, ty: RevealedTy<'tcx>, @@ -775,7 +775,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } /// Convert back to a `thir::Pat` for diagnostic purposes. - pub(crate) fn hoist_pat_range(&self, range: &IntRange, ty: RevealedTy<'tcx>) -> Pat<'tcx> { + fn hoist_pat_range(&self, range: &IntRange, ty: RevealedTy<'tcx>) -> Pat<'tcx> { use MaybeInfiniteInt::*; let cx = self; let kind = if matches!((range.lo, range.hi), (NegInfinity, PosInfinity)) { @@ -811,9 +811,17 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { Pat { ty: ty.inner(), span: DUMMY_SP, kind } } + + /// Prints a [`WitnessPat`] to an owned string, for diagnostic purposes. + pub fn print_witness_pat(&self, pat: &WitnessPat<'p, 'tcx>) -> String { + // This works by converting the witness pattern back to a `thir::Pat` + // and then printing that, but callers don't need to know that. + self.hoist_witness_pat(pat).to_string() + } + /// Convert back to a `thir::Pat` for diagnostic purposes. This panics for patterns that don't /// appear in diagnostics, like float ranges. - pub fn hoist_witness_pat(&self, pat: &WitnessPat<'p, 'tcx>) -> Pat<'tcx> { + fn hoist_witness_pat(&self, pat: &WitnessPat<'p, 'tcx>) -> Pat<'tcx> { let cx = self; let is_wildcard = |pat: &Pat<'_>| matches!(pat.kind, PatKind::Wild); let mut subpatterns = pat.iter_fields().map(|p| Box::new(cx.hoist_witness_pat(p))); From ae0ec731a86ac6a2f6d8d08c4996bb8a438afdc2 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 28 Jul 2024 14:02:41 +1000 Subject: [PATCH 29/33] Make `thir::Pat` not implement `fmt::Display` directly This gives a clearer view of the (diagnostic) code that expects to be able to print THIR patterns, and makes it possible to experiment with requiring some kind of context (for ID lookup) when printing patterns. --- compiler/rustc_middle/src/thir.rs | 65 ++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 1300a06f37510..9b63b3980d20f 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -1073,8 +1073,33 @@ impl<'tcx> PatRangeBoundary<'tcx> { } } -impl<'tcx> fmt::Display for Pat<'tcx> { +impl<'tcx> Pat<'tcx> { + /// Prints a [`Pat`] to an owned string, for user-facing diagnostics. + /// + /// If we ever switch over to storing subpatterns as `PatId`, this will also + /// need to take a context that can resolve IDs to subpatterns. + pub fn to_string(&self) -> String { + format!("{}", self.display()) + } + + /// Used internally by [`fmt::Display`] for [`PatDisplay`]. + fn display(&self) -> PatDisplay<'_, 'tcx> { + PatDisplay { pat: self } + } +} + +/// Wrapper around [`&Pat<'tcx>`][`Pat`] that implements [`fmt::Display`]. +/// +/// If we ever switch over to storing subpatterns as `PatId`, this will also +/// need to hold a context that can resolve IDs to subpatterns. +struct PatDisplay<'pat, 'tcx> { + pat: &'pat Pat<'tcx>, +} + +impl<'pat, 'tcx> fmt::Display for PatDisplay<'pat, 'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let &Self { pat } = self; + // Printing lists is a chore. let mut first = true; let mut start_or_continue = |s| { @@ -1087,20 +1112,22 @@ impl<'tcx> fmt::Display for Pat<'tcx> { }; let mut start_or_comma = || start_or_continue(", "); - match self.kind { + match pat.kind { PatKind::Wild => write!(f, "_"), PatKind::Never => write!(f, "!"), - PatKind::AscribeUserType { ref subpattern, .. } => write!(f, "{subpattern}: _"), + PatKind::AscribeUserType { ref subpattern, .. } => { + write!(f, "{}: _", subpattern.display()) + } PatKind::Binding { name, mode, ref subpattern, .. } => { f.write_str(mode.prefix_str())?; write!(f, "{name}")?; if let Some(ref subpattern) = *subpattern { - write!(f, " @ {subpattern}")?; + write!(f, " @ {}", subpattern.display())?; } Ok(()) } PatKind::Variant { ref subpatterns, .. } | PatKind::Leaf { ref subpatterns } => { - let variant_and_name = match self.kind { + let variant_and_name = match pat.kind { PatKind::Variant { adt_def, variant_index, .. } => ty::tls::with(|tcx| { let variant = adt_def.variant(variant_index); let adt_did = adt_def.did(); @@ -1113,7 +1140,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> { }; Some((variant, name)) }), - _ => self.ty.ty_adt_def().and_then(|adt_def| { + _ => pat.ty.ty_adt_def().and_then(|adt_def| { if !adt_def.is_enum() { ty::tls::with(|tcx| { Some((adt_def.non_enum_variant(), tcx.def_path_str(adt_def.did()))) @@ -1138,11 +1165,11 @@ impl<'tcx> fmt::Display for Pat<'tcx> { continue; } let name = variant.fields[p.field].name; - write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?; + write!(f, "{}{}: {}", start_or_comma(), name, p.pattern.display())?; printed += 1; } - let is_union = self.ty.ty_adt_def().is_some_and(|adt| adt.is_union()); + let is_union = pat.ty.ty_adt_def().is_some_and(|adt| adt.is_union()); if printed < variant.fields.len() && (!is_union || printed == 0) { write!(f, "{}..", start_or_comma())?; } @@ -1161,14 +1188,14 @@ impl<'tcx> fmt::Display for Pat<'tcx> { // Common case: the field is where we expect it. if let Some(p) = subpatterns.get(i) { if p.field.index() == i { - write!(f, "{}", p.pattern)?; + write!(f, "{}", p.pattern.display())?; continue; } } // Otherwise, we have to go looking for it. if let Some(p) = subpatterns.iter().find(|p| p.field.index() == i) { - write!(f, "{}", p.pattern)?; + write!(f, "{}", p.pattern.display())?; } else { write!(f, "_")?; } @@ -1179,45 +1206,45 @@ impl<'tcx> fmt::Display for Pat<'tcx> { Ok(()) } PatKind::Deref { ref subpattern } => { - match self.ty.kind() { + match pat.ty.kind() { ty::Adt(def, _) if def.is_box() => write!(f, "box ")?, ty::Ref(_, _, mutbl) => { write!(f, "&{}", mutbl.prefix_str())?; } - _ => bug!("{} is a bad Deref pattern type", self.ty), + _ => bug!("{} is a bad Deref pattern type", pat.ty), } - write!(f, "{subpattern}") + write!(f, "{}", subpattern.display()) } PatKind::DerefPattern { ref subpattern, .. } => { - write!(f, "deref!({subpattern})") + write!(f, "deref!({})", subpattern.display()) } PatKind::Constant { value } => write!(f, "{value}"), PatKind::InlineConstant { def: _, ref subpattern } => { - write!(f, "{} (from inline const)", subpattern) + write!(f, "{} (from inline const)", subpattern.display()) } PatKind::Range(ref range) => write!(f, "{range}"), PatKind::Slice { ref prefix, ref slice, ref suffix } | PatKind::Array { ref prefix, ref slice, ref suffix } => { write!(f, "[")?; for p in prefix.iter() { - write!(f, "{}{}", start_or_comma(), p)?; + write!(f, "{}{}", start_or_comma(), p.display())?; } if let Some(ref slice) = *slice { write!(f, "{}", start_or_comma())?; match slice.kind { PatKind::Wild => {} - _ => write!(f, "{slice}")?, + _ => write!(f, "{}", slice.display())?, } write!(f, "..")?; } for p in suffix.iter() { - write!(f, "{}{}", start_or_comma(), p)?; + write!(f, "{}{}", start_or_comma(), p.display())?; } write!(f, "]") } PatKind::Or { ref pats } => { for pat in pats.iter() { - write!(f, "{}{}", start_or_continue(" | "), pat)?; + write!(f, "{}{}", start_or_continue(" | "), pat.display())?; } Ok(()) } From 6e247195c644aa924a10c98cc8eb3a28e1a87929 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 25 Jul 2024 15:59:25 +0300 Subject: [PATCH 30/33] handle no_std targets on std builds This change unifies the `Step::run_make` logic and improves it by skipping std specific crates for no_std targets. Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/check.rs | 4 ++-- src/bootstrap/src/core/build_steps/clippy.rs | 3 ++- src/bootstrap/src/core/build_steps/compile.rs | 23 +++++++++++++++---- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 11ddae2aa2413..8b71300cf85e7 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -3,7 +3,7 @@ use std::path::PathBuf; use crate::core::build_steps::compile::{ - add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, + add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, std_crates_for_run_make, }; use crate::core::build_steps::tool::{prepare_tool_cargo, SourceType}; use crate::core::builder::{ @@ -49,7 +49,7 @@ impl Step for Std { } fn make_run(run: RunConfig<'_>) { - let crates = run.make_run_crates(Alias::Library); + let crates = std_crates_for_run_make(&run); run.builder.ensure(Std { target: run.target, crates, override_build_kind: None }); } diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index e45b44b82ded1..4ee9fbc314263 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -4,6 +4,7 @@ use super::compile::{librustc_stamp, libstd_stamp, run_cargo, rustc_cargo, std_c use super::tool::{prepare_tool_cargo, SourceType}; use super::{check, compile}; use crate::builder::{Builder, ShouldRun}; +use crate::core::build_steps::compile::std_crates_for_run_make; use crate::core::builder; use crate::core::builder::{crate_description, Alias, Kind, RunConfig, Step}; use crate::{Mode, Subcommand, TargetSelection}; @@ -106,7 +107,7 @@ impl Step for Std { } fn make_run(run: RunConfig<'_>) { - let crates = run.make_run_crates(Alias::Library); + let crates = std_crates_for_run_make(&run); run.builder.ensure(Std { target: run.target, crates }); } diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index ce456a7200223..3164de8451ff2 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -123,11 +123,7 @@ impl Step for Std { } fn make_run(run: RunConfig<'_>) { - // If the paths include "library", build the entire standard library. - let has_alias = - run.paths.iter().any(|set| set.assert_single_path().path.ends_with("library")); - let crates = if has_alias { Default::default() } else { run.cargo_crates_in_set() }; - + let crates = std_crates_for_run_make(&run); run.builder.ensure(Std { compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), target: run.target, @@ -425,6 +421,23 @@ fn copy_self_contained_objects( target_deps } +/// Resolves standard library crates for `Std::run_make` for any build kind (like check, build, clippy, etc.). +pub fn std_crates_for_run_make(run: &RunConfig<'_>) -> Vec { + let has_alias = run.paths.iter().any(|set| set.assert_single_path().path.ends_with("library")); + let target_is_no_std = run.builder.no_std(run.target).unwrap_or(false); + + // For no_std targets, do not add any additional crates to the compilation other than what `compile::std_cargo` already adds for no_std targets. + if target_is_no_std { + vec![] + } + // If the paths include "library", build the entire standard library. + else if has_alias { + run.make_run_crates(builder::Alias::Library) + } else { + run.cargo_crates_in_set() + } +} + /// Configure cargo to compile the standard library, adding appropriate env vars /// and such. pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, cargo: &mut Cargo) { From 4c87e84f998378f125222f876ef454a71861a7f4 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 25 Jul 2024 16:04:36 +0300 Subject: [PATCH 31/33] allow running `x doc` on std for no_std targets Since we now handle library crates properly, there's no need to panic for `no_std` targets anymore. `x doc library` now generates documentation for the `alloc` crate from standard library. Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/doc.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 0b780dae9c29a..53925a3f54b8a 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -589,6 +589,7 @@ impl Step for Std { } fn make_run(run: RunConfig<'_>) { + let crates = compile::std_crates_for_run_make(&run); run.builder.ensure(Std { stage: run.builder.top_stage, target: run.target, @@ -597,7 +598,7 @@ impl Step for Std { } else { DocumentationFormat::Html }, - crates: run.make_run_crates(Alias::Library), + crates, }); } @@ -695,13 +696,6 @@ fn doc_std( extra_args: &[&str], requested_crates: &[String], ) { - if builder.no_std(target) == Some(true) { - panic!( - "building std documentation for no_std target {target} is not supported\n\ - Set `docs = false` in the config to disable documentation, or pass `--skip library`." - ); - } - let compiler = builder.compiler(stage, builder.config.build); let target_doc_dir_name = if format == DocumentationFormat::Json { "json-doc" } else { "doc" }; From d3aed2cdb4d4069ef7b6c5c74a3679817272a6ba Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Fri, 26 Jul 2024 08:48:46 +0300 Subject: [PATCH 32/33] remove the requirement of `Builder` arg in `doc::Std::new` function `crates` field is handled in the `Step::make_run` just like in any other `Std` implementation, so we don't need to resolve them in `Std::new`. Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/dist.rs | 1 - src/bootstrap/src/core/build_steps/doc.rs | 14 ++------------ src/bootstrap/src/core/build_steps/test.rs | 1 - src/bootstrap/src/core/builder/tests.rs | 4 ---- 4 files changed, 2 insertions(+), 18 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index f971bf115ee92..967ddbc0d3483 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -106,7 +106,6 @@ impl Step for JsonDocs { builder.ensure(crate::core::build_steps::doc::Std::new( builder.top_stage, host, - builder, DocumentationFormat::Json, )); diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 53925a3f54b8a..1541396bfdd98 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -564,18 +564,8 @@ pub struct Std { } impl Std { - pub(crate) fn new( - stage: u32, - target: TargetSelection, - builder: &Builder<'_>, - format: DocumentationFormat, - ) -> Self { - let crates = builder - .in_tree_crates("sysroot", Some(target)) - .into_iter() - .map(|krate| krate.name.to_string()) - .collect(); - Std { stage, target, format, crates } + pub(crate) fn new(stage: u32, target: TargetSelection, format: DocumentationFormat) -> Self { + Std { stage, target, format, crates: vec![] } } } diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 79b7dd78810d2..ec96307deb285 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -847,7 +847,6 @@ impl Step for RustdocJSStd { builder.ensure(crate::core::build_steps::doc::Std::new( builder.top_stage, self.target, - builder, DocumentationFormat::Html, )); let _guard = builder.msg( diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index a295c89730acb..f19a4dd6d490f 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -79,13 +79,9 @@ macro_rules! std { macro_rules! doc_std { ($host:ident => $target:ident, stage = $stage:literal) => {{ - let config = configure("doc", &["A-A"], &["A-A"]); - let build = Build::new(config); - let builder = Builder::new(&build); doc::Std::new( $stage, TargetSelection::from_user(concat!(stringify!($target), "-", stringify!($target))), - &builder, DocumentationFormat::Html, ) }}; From f56d58e4a784b6429e742a411c2759900741894d Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Fri, 26 Jul 2024 08:54:55 +0300 Subject: [PATCH 33/33] ignore `crates` if running unit tests Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/compile.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 3164de8451ff2..268e89c7f6011 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -423,6 +423,11 @@ fn copy_self_contained_objects( /// Resolves standard library crates for `Std::run_make` for any build kind (like check, build, clippy, etc.). pub fn std_crates_for_run_make(run: &RunConfig<'_>) -> Vec { + // FIXME: Extend builder tests to cover the `crates` field of `Std` instances. + if cfg!(feature = "bootstrap-self-test") { + return vec![]; + } + let has_alias = run.paths.iter().any(|set| set.assert_single_path().path.ends_with("library")); let target_is_no_std = run.builder.no_std(run.target).unwrap_or(false);