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 000000000000..1f52537f9a29 --- /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 86074384084d..4d9595b352f2 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 @@ fn from_ref_ty( ) -> 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 @@ fn from_ref_ty( _ => 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 7aa9c3e862bc..9c19ae76a2d0 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 7d000ba55e60..ce9a5b7f1586 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 1f52537f9a29..5e7cb5e34cc2 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 inner(y: &mut Cell, b: IdxBarrier) -> *mut u8 { 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 000000000000..9be6c157c0cb --- /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 0d0d52c717fe..d149a4065f92 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 4d9595b352f2..123d4b407fb4 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 @@ fn from_ref_ty( // 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 5e7cb5e34cc2..611f64dce5e5 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 @@ // 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 inner(x: &mut u8, b: IdxBarrier, 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 000000000000..5ac9c912ba9e --- /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 9be6c157c0cb..97c71fdedefb 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 611f64dce5e5..6ae79be6cc7e 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 inner(x: &mut u8, b: IdxBarrier) { 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 5ac9c912ba9e..0e4517e90105 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 97c71fdedefb..cbeef90243bf 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 6ae79be6cc7e..73f227fee2fc 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 9c19ae76a2d0..8e23257b6c00 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 @@ fn child_write(state: PermissionPriv, protected: bool) -> Option /// 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 e90d3732ca57..2c29af8b9357 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 2c29af8b9357..b09d4f11f68e 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 e34aa5c09dfe..d1218114e0d7 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -266,7 +266,8 @@ fn open(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, i32> { 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 @@ fn open(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, i32> { 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 d72edd7d9e3f..96ced05cd1e8 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 @@ 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 eddea92353e3..5b2bbfbb27d0 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 96ced05cd1e8..619c6db3a29d 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 | 91 +++++++++++++++---- .../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, 204 insertions(+), 20 deletions(-) diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs index 8fb046b5e64c..de6d27f5290d 100644 --- a/src/tools/miri/src/shims/unix/fd.rs +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -36,6 +36,30 @@ fn write<'tcx>( 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 @@ fn fd_not_found>(&mut self) -> InterpResult<'tcx, T> { 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 @@ fn read(&mut self, fd: i32, buf: Pointer, count: u64) -> InterpResult<'tcx, i64> 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); + 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); - match result { + // `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 @@ fn read(&mut self, fd: i32, buf: Pointer, count: u64) -> InterpResult<'tcx, i64> } } - 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 @@ fn write(&mut self, fd: i32, buf: Pointer, count: u64) -> InterpResult<'tcx, i64 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 3a18d6220333..966e590fcc41 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 @@ fn emulate_foreign_item_inner( 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 @@ fn emulate_foreign_item_inner( 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 e34aa5c09dfe..80268ced48de 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -49,6 +49,54 @@ fn write<'tcx>( 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 16d3e8cab30a..70e375b09812 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 b09d4f11f68e..60497630ae0d 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 7ad395cccb79..6586ea8e48cf 100644 --- a/src/tools/miri/src/shims/env.rs +++ b/src/tools/miri/src/shims/env.rs @@ -108,4 +108,9 @@ fn get_env_var(&mut self, name: &OsStr) -> InterpResult<'tcx, Option> 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 405431f4327d..3b8ad65195b8 100644 --- a/src/tools/miri/src/shims/unix/env.rs +++ b/src/tools/miri/src/shims/unix/env.rs @@ -274,12 +274,23 @@ fn getpid(&mut self) -> InterpResult<'tcx, i32> { 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 95bee38cd783..20c6a2347942 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 @@ fn emulate_foreign_item_inner( )?; 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 ed3eb6979863..77ae06bd5c2d 100644 --- a/src/tools/miri/src/shims/windows/env.rs +++ b/src/tools/miri/src/shims/windows/env.rs @@ -200,9 +200,8 @@ fn SetCurrentDirectoryW( 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 000000000000..87405b02ac35 --- /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 733545462ebc..f350fafff4a2 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 603733f9dc00..1d75486a7818 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 @@ mod item; mod stack; +use std::cell::RefCell; use std::cmp; use std::fmt::Write; use std::mem; @@ -820,7 +821,19 @@ fn sb_retag_place( // 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 647d7d44bb1b..45a8a54bc298 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 @@ pub fn emit_diagnostic(&self, e: NonHaltingDiagnostic) { 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 @@ pub fn emit_diagnostic(&self, e: NonHaltingDiagnostic) { 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 @@ pub fn emit_diagnostic(&self, e: NonHaltingDiagnostic) { ( 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 3ed5732b4eb0..c07b63e0c038 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 217bc82010df..84023cf79371 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 341f84c8992d..f2d01b518fc8 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 03a9167abbc7..9b6f632eb5a2 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 b0e1adf27d18..216bb6c76bc9 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 60497630ae0d..9868188eeee7 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 9868188eeee7..e1a6084b22ed 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 9f3fa075f38f..25b154a8206c 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 c9e7e300593b..d537a7fbc179 100644 --- a/src/tools/miri/src/borrow_tracker/mod.rs +++ b/src/tools/miri/src/borrow_tracker/mod.rs @@ -232,6 +232,10 @@ pub fn root_ptr_tag(&mut self, id: AllocId, machine: &MiriMachine<'_>) -> BorTag 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 45a8a54bc298..6d10a21293b6 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -647,8 +647,8 @@ pub fn emit_diagnostic(&self, e: NonHaltingDiagnostic) { }; let helps = match &e { - Int2Ptr { details: true } => - vec![ + Int2Ptr { details: true } => { + let mut v = vec![ ( None, format!( @@ -673,13 +673,26 @@ pub fn emit_diagnostic(&self, e: NonHaltingDiagnostic) { "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 8be4bdac7e1b..711c54fd68ad 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 174bf8be30b2..693209c04568 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 f2d01b518fc8..000000000000 --- 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 230ef368da64..000000000000 --- 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 7ac93577f0cd..eade5c6ac087 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 9b6f632eb5a2..2c9fc0192af8 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 fb1a1dfae5d1..a304f2751bdb 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 c7b720dafa20..280a815abc43 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 a2fcd098107a..684e8f6ec7bd 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 000000000000..a34474ee0d62 --- /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 5690d7865bbc..f6ebf0632a17 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 000000000000..614b0d26a630 --- /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 6d10a21293b6..1bed55743d4a 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 @@ pub fn emit_diagnostic(&self, e: NonHaltingDiagnostic) { 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 @@ pub fn emit_diagnostic(&self, e: NonHaltingDiagnostic) { 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 adb845935616..e492793a6513 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -660,7 +660,7 @@ pub(crate) fn new(config: &MiriConfig, layout_cx: LayoutCx<'tcx, TyCtxt<'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 de6d27f5290d..0fffecd99d5c 100644 --- a/src/tools/miri/src/shims/unix/fd.rs +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -192,10 +192,6 @@ fn write<'tcx>( 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 @@ fn visit_provenance(&self, _visit: &mut VisitWith<'_>) { } 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 9ea7f9c37ea1..6923b39733f0 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::*; use shims::time::system_time_to_duration; -use self::fd::FileDescriptor; - #[derive(Debug)] struct FileHandle { file: File, @@ -452,10 +450,9 @@ fn open(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, i32> { 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 @@ fn mkstemp(&mut self, template_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { 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 a5661460e95c..ad35d67876cc 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 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 @@ fn epoll_create1(&mut self, flags: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { ); } - 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 cae5abca3bd0..0fc28c72bb6f 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 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 @@ fn eventfd(&mut self, val: &OpTy<'tcx>, flags: &OpTy<'tcx>) -> InterpResult<'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 6d3d63b4efa0..cc0f932e0382 100644 --- a/src/tools/miri/src/shims/unix/socket.rs +++ b/src/tools/miri/src/shims/unix/socket.rs @@ -7,8 +7,6 @@ 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 @@ fn socketpair( }; 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 e1a6084b22ed..58ec4e10856d 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 0bbf2a8e13e9..1bd32fce8bd9 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 cd269810741e..a93911225e41 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 b227565f8f91..0b4a21d972cd 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -243,36 +243,22 @@ pub fn emulate_intrinsic( 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) + // Neither pointer points to an allocation, so they are both absolute. + (a, b, /*is_addr*/ true) } - _ 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) - } - // 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 @@ pub fn emulate_intrinsic( 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 @@ pub fn emulate_intrinsic( 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 @@ pub fn emulate_intrinsic( } }; - // 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 @@ pub fn saturating_arith( } /// 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 36fe8dfdd29b..0d85e8ef6646 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -414,6 +414,25 @@ pub fn check_ptr_access( 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 57b4fd0dedb7..c307dfddb6c1 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 6e9e5633fecc..65f1161425ff 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 06d13d9bdbaf..13eb5bfb3421 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 0b4a9faf1b24..e436f9029d50 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 5690d7865bbc..589ef781a91a 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 1506c212fbae..95b3118f1570 100644 --- a/tests/ui/consts/offset_from_ub.rs +++ b/tests/ui/consts/offset_from_ub.rs @@ -36,7 +36,7 @@ struct Struct { 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 7b623126d54f..0a860f42c649 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 ebc7019a75aa..9a8f756749b7 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 a93911225e41..43f405b22350 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 292d6ba9d08a..922225e22d90 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -7,9 +7,9 @@ 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 @@ fn diagnostic_message(&self) -> DiagMessage { 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 @@ fn add_args(self, diag: &mut Diag<'_, G>) { 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 0d85e8ef6646..f49a0ed727a8 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -459,7 +459,7 @@ fn check_and_deref_ptr( 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 @@ fn check_and_deref_ptr( alloc_id, alloc_size, ptr_offset: self.target_usize_to_isize(offset.bytes()), - ptr_size: size, + inbounds_size: size, msg, }) } @@ -1443,7 +1443,13 @@ pub fn ptr_get_alloc_id( 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 3dc3e6c88332..879f9205cbf4 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -348,7 +348,7 @@ fn check_wide_ptr_meta( 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 @@ fn check_safe_pointer( 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 @@ fn try_visit_primitive( 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 9df19565ab38..68676e862ef0 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 a0acacc844fd..074245fcd32a 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 c01f15800fac..b9f79fdda89c 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 672cc10cd630..b6b4b62e6210 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 @@ // 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 b76722f5f8f1..f03ae33ed9f3 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 066af4a8ae3c..0e204aa7f094 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 @@ // 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 5c6ba4fd9797..4bca5a3db072 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 4ab37ab569fe..6adaaeb3dbf1 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 3e1ee7b86e31..b2da332df214 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 f06336b12995..1fe637d6ce7e 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 @@ // 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 0cc7ac19febc..a9ed58d61bb3 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 424aace239a2..49de3dd0b105 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 be01c5cc840f..07bb3293989e 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 be01c5cc840f..07bb3293989e 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 e96e641bb0d3..04494b525617 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 e96e641bb0d3..04494b525617 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 37f2bb395576..a5c031b94964 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 377022fa97f3..d989bff4516f 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 a0773c63cf6b..dee05952a993 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 a18f0f20fc01..1b97265eb32f 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 954596f57542..61f5ef572cf3 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 01d4d12a002d..3d75e7a0254b 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 4195c68d500d..bdd245e18494 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 658fbd16c2e8..595a229baa5a 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 37dbea37ce2d..8a774c21bb7c 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 2ff537b1ffc5..054e1c66cc18 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 97b3f3ebe7b5..6ae9f05d1738 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 73c3ff1ee051..2d4fbafd8b7f 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 b7492a09dd09..1d8eed3d30a7 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 7274f62b4d7c..347afa77053e 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 b6a110ee84d2..f337090aa1e3 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 cc8cca70ddb9..ddc5ae8efbc0 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 701bc33a645e..fc9fb3d35d61 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 236b51e82e59..88963e712f4c 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 65f1161425ff..649075dbc55d 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 e03abfb1a2fc..8d37da650613 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 fd3c9b44615c..c4b6f69dd2be 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 03ae9bd141c4..2cd02bee2ca1 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 ceb7beebd8ab..b83739524517 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 d111644eec82..bc8d0b041d32 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 98b6749c584f..bb8c9dbe4c7a 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 8b517b6e9725..aae77edcb6bd 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 50bff22f7667..1ca35be8cb2b 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 6b1c2941c075..8a1d39effbd1 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 92ccec502749..e21872244f60 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 8b8033b0d1d9..bd0a9eb0d291 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 8ae140ee004c..35e5c08300f9 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 03f93510d09b..cba8a9f84396 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 843d0d11873d..75f7aae9718d 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 @@ 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 04dbd657d200..523c935762ff 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 cc81481e4fa4..ab48b7d330b3 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 ba1ccaa0a3c8..39ac2c91437c 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 eb41a25c818a..034e8bd18526 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 7634ba252100..7f354963eb1f 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 9e49706c4c83..8a923779a5bb 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 b102b4d17cca..070685e0b9d9 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 e6cd25e42ff7..b0c864652e55 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 b878c8d1b376..bd6dafb93665 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 d7d24f373ebc..25f17f9c38a9 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 22679acda98b..0fb9694895d8 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 47105de453cb..5aced5b1bd6d 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 @@ 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 cba06fdc639f..5fce25701bdd 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 ab0fb2abdb30..fe3060dda17d 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 4fe744265dfb..c29cc836fffd 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 4183dc0fcd6d..e3f43ce20375 100644 --- a/tests/ui/consts/copy-intrinsic.rs +++ b/tests/ui/consts/copy-intrinsic.rs @@ -27,7 +27,7 @@ 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 @@ 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 d34e61cd9627..2dbb471131ec 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 95b3118f1570..66bb056ceb04 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 @@ struct Struct { 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 @@ struct Struct { 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 0a860f42c649..f2f27735630f 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 9a8f756749b7..b239b91e11cf 100644 --- a/tests/ui/consts/offset_ub.rs +++ b/tests/ui/consts/offset_ub.rs @@ -2,6 +2,7 @@ //@ 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 89371f06d9d6..b42d9482f8a0 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 2f8ea7993f72..c14f4948095d 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 b80d00719ee5..1300a06f3751 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 @@ pub fn is_never_pattern(&self) -> bool { } } -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 bdc4b0ea97d1..2e508829fbe3 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 27f227e6d9c1..bad41ac77f09 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 @@ #[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 @@ pub fn new<'p>( 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 @@ pub fn new<'p>( #[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 @@ fn add_to_diag_with>( #[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 @@ fn add_to_diag_with>( 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 910dd4c6c1a8..ceddafa2f4ce 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -966,7 +966,7 @@ fn lint_overlapping_range_endpoints( 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 @@ fn lint_non_contiguous_range_endpoints( // 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 @@ fn lint_non_contiguous_range_endpoints( // 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 @@ fn lint_non_contiguous_range_endpoints( .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 9849410d484c..f0d2c761ef35 100644 --- a/library/core/src/ops/deref.rs +++ b/library/core/src/ops/deref.rs @@ -282,7 +282,7 @@ fn deref_mut(&mut self) -> &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 da6b541a9870..2566beeadac5 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -786,7 +786,7 @@ pub fn with_exposed_provenance_mut(addr: usize) -> *mut T /// /// 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 5f75e1944122..067daa6a0d09 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -3452,8 +3452,8 @@ pub fn rotate_left(&mut self, mid: usize) { /// 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 3b039786eb5e..6c5859460500 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 e8f08db94164..a3eca34a35cf 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 57247359fbf2..10dcaa8cd3aa 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 353fd8d2de8c..7240605bfd65 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 71cb796b9370..db87d923de0e 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 da7b029ca732..3acc09e0b9b1 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 5e904057e732..0632911671e1 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 bad41ac77f09..1f7852e5190d 100644 --- a/compiler/rustc_pattern_analysis/src/errors.rs +++ b/compiler/rustc_pattern_analysis/src/errors.rs @@ -26,19 +26,13 @@ pub fn new<'p, 'tcx>( 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 ceddafa2f4ce..b04c21a384c8 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -744,7 +744,7 @@ pub fn lower_pat(&self, pat: &'p Pat<'tcx>) -> DeconstructedPat<'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 @@ pub(crate) fn hoist_pat_range_bdy( } /// 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 @@ pub(crate) fn hoist_pat_range(&self, range: &IntRange, ty: RevealedTy<'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 1300a06f3751..9b63b3980d20 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -1073,8 +1073,33 @@ pub fn compare_with( } } -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 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { }; 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 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { }; 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 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 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 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // 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 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 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 11ddae2aa241..8b71300cf85e 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 @@ fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { } 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 e45b44b82ded..4ee9fbc31426 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::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 @@ fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { } 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 ce456a720022..3164de8451ff 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -123,11 +123,7 @@ fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { } 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 0b780dae9c29..53925a3f54b8 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -589,6 +589,7 @@ fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { } 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 @@ fn make_run(run: RunConfig<'_>) { } 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 f971bf115ee9..967ddbc0d348 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -106,7 +106,6 @@ fn run(self, builder: &Builder<'_>) -> Option { 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 53925a3f54b8..1541396bfdd9 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 79b7dd78810d..ec96307deb28 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -847,7 +847,6 @@ fn run(self, builder: &Builder<'_>) { 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 a295c89730ac..f19a4dd6d490 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 3164de8451ff..268e89c7f601 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);