From 076de8724187e6b894352313fadb2b7c223a4027 Mon Sep 17 00:00:00 2001 From: Mohamed Ali Date: Fri, 24 Jul 2026 12:17:07 +0300 Subject: [PATCH 01/23] [Priroda] Add source-shaped value UI coverage Add UI coverage for source-shaped local values before changing the renderer. The new cases exercise structs, enum variants, tuples, arrays, slices, and fallback leaf values so later commits can bless one behavior change at a time. --- .../priroda/tests/ui/locals_source_shapes.rs | 72 +++++++++++++++++++ .../tests/ui/locals_source_shapes.stdin | 22 ++++++ .../tests/ui/locals_source_shapes.stdout | 62 ++++++++++++++++ .../priroda/tests/ui/locals_source_slices.rs | 20 ++++++ .../tests/ui/locals_source_slices.stdin | 13 ++++ .../tests/ui/locals_source_slices.stdout | 25 +++++++ .../priroda/tests/ui/locals_value_shapes.rs | 34 ++++++++- .../tests/ui/locals_value_shapes.stdin | 9 ++- .../tests/ui/locals_value_shapes.stdout | 45 +++++++++--- 9 files changed, 289 insertions(+), 13 deletions(-) create mode 100644 src/tools/miri/priroda/tests/ui/locals_source_shapes.rs create mode 100644 src/tools/miri/priroda/tests/ui/locals_source_shapes.stdin create mode 100644 src/tools/miri/priroda/tests/ui/locals_source_shapes.stdout create mode 100644 src/tools/miri/priroda/tests/ui/locals_source_slices.rs create mode 100644 src/tools/miri/priroda/tests/ui/locals_source_slices.stdin create mode 100644 src/tools/miri/priroda/tests/ui/locals_source_slices.stdout diff --git a/src/tools/miri/priroda/tests/ui/locals_source_shapes.rs b/src/tools/miri/priroda/tests/ui/locals_source_shapes.rs new file mode 100644 index 0000000000000..a90de2d0fa531 --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/locals_source_shapes.rs @@ -0,0 +1,72 @@ +#![allow(dead_code, unused_variables)] + +struct Named { + a: u8, + b: u16, +} + +struct EmptyBraced {} + +struct UnitStruct; + +struct TupleStruct(u8, u16); + +struct SingleTupleStruct(u8); + +struct ZeroTupleStruct(); + +enum Variants { + Unit, + Tuple(u8, u16), + SingleTuple(u8), + Struct { n: u32, ok: bool }, + EmptyStruct {}, +} + +union RawUnion { + byte: u8, + word: u16, +} + +fn main() { + let named = Named { a: 0x01, b: 0x0302 }; + let empty_braced = EmptyBraced {}; + let unit_struct = UnitStruct; + let tuple_struct = TupleStruct(0x04, 0x0605); + let single_tuple_struct = SingleTupleStruct(0x07); + let zero_tuple_struct = ZeroTupleStruct(); + let tuple_zero = (); + let tuple_one = (0x08_u8,); + let tuple_many = (0x09_u8, 0x0b0a_u16); + let array_zero: [u8; 0] = []; + let array_one = [0x0c_u8]; + let array_many = [0x0d_u8, 0x0e, 0x0f]; + let variant_unit = Variants::Unit; + let variant_tuple = Variants::Tuple(0x10, 0x1211); + let variant_single_tuple = Variants::SingleTuple(0x13); + let variant_struct = Variants::Struct { n: 0x17161514, ok: false }; + let variant_empty_struct = Variants::EmptyStruct {}; + let raw_union = RawUnion { word: 0x1918 }; + + std::hint::black_box(( + &named, + &empty_braced, + &unit_struct, + &tuple_struct, + &single_tuple_struct, + &zero_tuple_struct, + &tuple_zero, + &tuple_one, + &tuple_many, + &array_zero, + &array_one, + &array_many, + &variant_unit, + &variant_tuple, + &variant_single_tuple, + &variant_struct, + &variant_empty_struct, + &raw_union, + )); + std::hint::black_box(0_u8); +} diff --git a/src/tools/miri/priroda/tests/ui/locals_source_shapes.stdin b/src/tools/miri/priroda/tests/ui/locals_source_shapes.stdin new file mode 100644 index 0000000000000..597b95492d3a4 --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/locals_source_shapes.stdin @@ -0,0 +1,22 @@ +break tests/ui/locals_source_shapes.rs:71 +continue +locals +print 1 +print 2 +print 3 +print 4 +print 5 +print 6 +print 7 +print 8 +print 9 +print 10 +print 11 +print 12 +print 13 +print 14 +print 15 +print 16 +print 17 +print 18 +quit diff --git a/src/tools/miri/priroda/tests/ui/locals_source_shapes.stdout b/src/tools/miri/priroda/tests/ui/locals_source_shapes.stdout new file mode 100644 index 0000000000000..7482832a65c6b --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/locals_source_shapes.stdout @@ -0,0 +1,62 @@ +(priroda) breakpoint added: {MANIFEST_DIR}/tests/ui/locals_source_shapes.rs:71 +(priroda) Hit breakpoint +{MANIFEST_DIR}/tests/ui/locals_source_shapes.rs:71 +(priroda) Name: , Id: _0, Ty: (), Value: +Name: named, Id: _1, Ty: Named, Value: [02 03 01 __] +Name: empty_braced, Id: _2, Ty: EmptyBraced, Value: [] +Name: unit_struct, Id: _3, Ty: UnitStruct, Value: [] +Name: tuple_struct, Id: _4, Ty: TupleStruct, Value: [05 06 04 __] +Name: single_tuple_struct, Id: _5, Ty: SingleTupleStruct, Value: [07] +Name: zero_tuple_struct, Id: _6, Ty: ZeroTupleStruct, Value: [] +Name: tuple_zero, Id: _7, Ty: (), Value: [] +Name: tuple_one, Id: _8, Ty: (u8,), Value: [08] +Name: tuple_many, Id: _9, Ty: (u8, u16), Value: [09 __ 0a 0b] +Name: array_zero, Id: _10, Ty: [u8; 0], Value: [] +Name: array_one, Id: _11, Ty: [u8; 1], Value: [0c] +Name: array_many, Id: _12, Ty: [u8; 3], Value: [0d 0e 0f] +Name: variant_unit, Id: _13, Ty: Variants, Value: [00 __ __ __ __ __ __ __] +Name: variant_tuple, Id: _14, Ty: Variants, Value: [01 10 11 12 __ __ __ __] +Name: variant_single_tuple, Id: _15, Ty: Variants, Value: [02 13 __ __ __ __ __ __] +Name: variant_struct, Id: _16, Ty: Variants, Value: [03 00 __ __ 14 15 16 17] +Name: variant_empty_struct, Id: _17, Ty: Variants, Value: [04 __ __ __ __ __ __ __] +Name: raw_union, Id: _18, Ty: RawUnion, Value: [18 19] +Name: , Id: _19, Ty: (&Named, &EmptyBraced, &UnitStruct, &TupleStruct, &SingleTupleStruct, &ZeroTupleStruct, &(), &(u8,), &(u8, u16), &[u8; 0], &[u8; 1], &[u8; 3], &Variants, &Variants, &Variants, &Variants, &Variants, &RawUnion), Value: +Name: , Id: _20, Ty: (&Named, &EmptyBraced, &UnitStruct, &TupleStruct, &SingleTupleStruct, &ZeroTupleStruct, &(), &(u8,), &(u8, u16), &[u8; 0], &[u8; 1], &[u8; 3], &Variants, &Variants, &Variants, &Variants, &Variants, &RawUnion), Value: +Name: , Id: _21, Ty: &Named, Value: +Name: , Id: _22, Ty: &EmptyBraced, Value: +Name: , Id: _23, Ty: &UnitStruct, Value: +Name: , Id: _24, Ty: &TupleStruct, Value: +Name: , Id: _25, Ty: &SingleTupleStruct, Value: +Name: , Id: _26, Ty: &ZeroTupleStruct, Value: +Name: , Id: _27, Ty: &(), Value: +Name: , Id: _28, Ty: &(u8,), Value: +Name: , Id: _29, Ty: &(u8, u16), Value: +Name: , Id: _30, Ty: &[u8; 0], Value: +Name: , Id: _31, Ty: &[u8; 1], Value: +Name: , Id: _32, Ty: &[u8; 3], Value: +Name: , Id: _33, Ty: &Variants, Value: +Name: , Id: _34, Ty: &Variants, Value: +Name: , Id: _35, Ty: &Variants, Value: +Name: , Id: _36, Ty: &Variants, Value: +Name: , Id: _37, Ty: &Variants, Value: +Name: , Id: _38, Ty: &RawUnion, Value: +Name: , Id: _39, Ty: u8, Value: +(priroda) Id: _1, Ty: Named, Value: [02 03 01 __] +(priroda) Id: _2, Ty: EmptyBraced, Value: [] +(priroda) Id: _3, Ty: UnitStruct, Value: [] +(priroda) Id: _4, Ty: TupleStruct, Value: [05 06 04 __] +(priroda) Id: _5, Ty: SingleTupleStruct, Value: [07] +(priroda) Id: _6, Ty: ZeroTupleStruct, Value: [] +(priroda) Id: _7, Ty: (), Value: [] +(priroda) Id: _8, Ty: (u8,), Value: [08] +(priroda) Id: _9, Ty: (u8, u16), Value: [09 __ 0a 0b] +(priroda) Id: _10, Ty: [u8; 0], Value: [] +(priroda) Id: _11, Ty: [u8; 1], Value: [0c] +(priroda) Id: _12, Ty: [u8; 3], Value: [0d 0e 0f] +(priroda) Id: _13, Ty: Variants, Value: [00 __ __ __ __ __ __ __] +(priroda) Id: _14, Ty: Variants, Value: [01 10 11 12 __ __ __ __] +(priroda) Id: _15, Ty: Variants, Value: [02 13 __ __ __ __ __ __] +(priroda) Id: _16, Ty: Variants, Value: [03 00 __ __ 14 15 16 17] +(priroda) Id: _17, Ty: Variants, Value: [04 __ __ __ __ __ __ __] +(priroda) Id: _18, Ty: RawUnion, Value: [18 19] +(priroda) quitting diff --git a/src/tools/miri/priroda/tests/ui/locals_source_slices.rs b/src/tools/miri/priroda/tests/ui/locals_source_slices.rs new file mode 100644 index 0000000000000..1afaf69c1f677 --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/locals_source_slices.rs @@ -0,0 +1,20 @@ +#![feature(unsized_fn_params)] +#![allow(incomplete_features, internal_features, unused_variables)] + +fn slice_zero(slice: [u8]) { + std::hint::black_box(&slice); +} + +fn slice_one(slice: [u8]) { + std::hint::black_box(&slice); +} + +fn slice_many(slice: [u8]) { + std::hint::black_box(&slice); +} + +fn main() { + slice_zero(*Box::<[u8]>::from([])); + slice_one(*Box::<[u8]>::from([0x1a_u8])); + slice_many(*Box::<[u8]>::from([0x1b_u8, 0x1c])); +} diff --git a/src/tools/miri/priroda/tests/ui/locals_source_slices.stdin b/src/tools/miri/priroda/tests/ui/locals_source_slices.stdin new file mode 100644 index 0000000000000..55c8864d4a38f --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/locals_source_slices.stdin @@ -0,0 +1,13 @@ +break tests/ui/locals_source_slices.rs:4 +break tests/ui/locals_source_slices.rs:8 +break tests/ui/locals_source_slices.rs:12 +continue +locals +print 1 +continue +locals +print 1 +continue +locals +print 1 +quit diff --git a/src/tools/miri/priroda/tests/ui/locals_source_slices.stdout b/src/tools/miri/priroda/tests/ui/locals_source_slices.stdout new file mode 100644 index 0000000000000..b7444efa9150e --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/locals_source_slices.stdout @@ -0,0 +1,25 @@ +(priroda) breakpoint added: {MANIFEST_DIR}/tests/ui/locals_source_slices.rs:4 +(priroda) breakpoint added: {MANIFEST_DIR}/tests/ui/locals_source_slices.rs:8 +(priroda) breakpoint added: {MANIFEST_DIR}/tests/ui/locals_source_slices.rs:12 +(priroda) Hit breakpoint +{MANIFEST_DIR}/tests/ui/locals_source_slices.rs:4 +(priroda) Name: , Id: _0, Ty: (), Value: +Name: slice, Id: _1, Ty: [u8], Value: [] +Name: , Id: _2, Ty: &[u8], Value: +Name: , Id: _3, Ty: &[u8], Value: +(priroda) Id: _1, Ty: [u8], Value: [] +(priroda) Hit breakpoint +{MANIFEST_DIR}/tests/ui/locals_source_slices.rs:8 +(priroda) Name: , Id: _0, Ty: (), Value: +Name: slice, Id: _1, Ty: [u8], Value: [1a] +Name: , Id: _2, Ty: &[u8], Value: +Name: , Id: _3, Ty: &[u8], Value: +(priroda) Id: _1, Ty: [u8], Value: [1a] +(priroda) Hit breakpoint +{MANIFEST_DIR}/tests/ui/locals_source_slices.rs:12 +(priroda) Name: , Id: _0, Ty: (), Value: +Name: slice, Id: _1, Ty: [u8], Value: [1b 1c] +Name: , Id: _2, Ty: &[u8], Value: +Name: , Id: _3, Ty: &[u8], Value: +(priroda) Id: _1, Ty: [u8], Value: [1b 1c] +(priroda) quitting diff --git a/src/tools/miri/priroda/tests/ui/locals_value_shapes.rs b/src/tools/miri/priroda/tests/ui/locals_value_shapes.rs index b6f00bd1e08cc..ea8b100a8a945 100644 --- a/src/tools/miri/priroda/tests/ui/locals_value_shapes.rs +++ b/src/tools/miri/priroda/tests/ui/locals_value_shapes.rs @@ -5,6 +5,19 @@ struct Aggregate { word: u16, } +struct TupleAggregate(u8, u16); + +struct Nested { + aggregate: Aggregate, + tuple: (u8, u16), +} + +enum Choice { + Unit, + Tuple(u8, u16), + Struct { n: u32, ok: bool }, +} + fn main() { // Edge case for `None` from `as_mplace_or_imm`: moved/drop temporaries become dead. let dead_box = Box::new(0x11_u8); @@ -23,8 +36,27 @@ fn main() { let scalar_pair = &[10_u8, 20_u8][..]; // Either::Left mplace/indirect storage. let mplace = Aggregate { byte: scalar, word: 0x1234 }; + let tuple = (0x01_u8, 0x0203_u16); + let tuple_struct = TupleAggregate(0x04_u8, 0x0506_u16); + let array = [0x07_u8, 0x08, 0x09]; + let nested = Nested { aggregate: Aggregate { byte: 0x0a, word: 0x0b0c }, tuple }; + let unit_variant = Choice::Unit; + let tuple_variant = Choice::Tuple(0x0d, 0x0e0f); + let struct_variant = Choice::Struct { n: 0x10111213, ok: true }; // Immediate::Uninit. let uninit_scalar: u32; - std::hint::black_box((scalar, scalar_pointer, scalar_pair.len(), &mplace)); + std::hint::black_box(( + scalar, + scalar_pointer, + scalar_pair.len(), + &mplace, + &tuple, + &tuple_struct, + &array, + &nested, + &unit_variant, + &tuple_variant, + &struct_variant, + )); } diff --git a/src/tools/miri/priroda/tests/ui/locals_value_shapes.stdin b/src/tools/miri/priroda/tests/ui/locals_value_shapes.stdin index fbd5687a45754..74bcb4b0b088a 100644 --- a/src/tools/miri/priroda/tests/ui/locals_value_shapes.stdin +++ b/src/tools/miri/priroda/tests/ui/locals_value_shapes.stdin @@ -1,4 +1,4 @@ -break tests/ui/locals_value_shapes.rs:29 +break tests/ui/locals_value_shapes.rs:49 continue locals print 0 @@ -8,5 +8,12 @@ print 7 print 8 print 13 print 15 +print 17 +print 18 +print 19 +print 20 +print 23 +print 24 +print 25 print 999 quit diff --git a/src/tools/miri/priroda/tests/ui/locals_value_shapes.stdout b/src/tools/miri/priroda/tests/ui/locals_value_shapes.stdout index 4250c443221f4..b9f01f637c67e 100644 --- a/src/tools/miri/priroda/tests/ui/locals_value_shapes.stdout +++ b/src/tools/miri/priroda/tests/ui/locals_value_shapes.stdout @@ -1,6 +1,6 @@ -(priroda) breakpoint added: {MANIFEST_DIR}/tests/ui/locals_value_shapes.rs:29 +(priroda) breakpoint added: {MANIFEST_DIR}/tests/ui/locals_value_shapes.rs:49 (priroda) Hit breakpoint -{MANIFEST_DIR}/tests/ui/locals_value_shapes.rs:29 +{MANIFEST_DIR}/tests/ui/locals_value_shapes.rs:49 (priroda) Name: , Id: _0, Ty: (), Value: Name: dead_box, Id: _1, Ty: std::boxed::Box, Value: [{ALLOC_PTR}] Name: consumed, Id: _2, Ty: std::boxed::Box, Value: [{ALLOC_PTR}] @@ -18,15 +18,31 @@ Name: , Id: _13, Ty: [u8; 2], Value: Name: , Id: _14, Ty: std::ops::RangeFull, Value: Name: mplace, Id: _15, Ty: Aggregate, Value: [34 12 2a __] Name: , Id: _16, Ty: u8, Value: -Name: uninit_scalar, Id: _17, Ty: u32, Value: -Name: , Id: _18, Ty: (u8, &u8, usize, &Aggregate), Value: -Name: , Id: _19, Ty: (u8, &u8, usize, &Aggregate), Value: -Name: , Id: _20, Ty: u8, Value: -Name: , Id: _21, Ty: &u8, Value: -Name: , Id: _22, Ty: usize, Value: -Name: , Id: _23, Ty: &[u8], Value: -Name: , Id: _24, Ty: &Aggregate, Value: -Name: , Id: _25, Ty: &[u8; 2], Value: {&_: &[u8; 2]} +Name: tuple, Id: _17, Ty: (u8, u16), Value: [01 __ 03 02] +Name: tuple_struct, Id: _18, Ty: TupleAggregate, Value: [06 05 04 __] +Name: array, Id: _19, Ty: [u8; 3], Value: [07 08 09] +Name: nested, Id: _20, Ty: Nested, Value: [0c 0b 0a __ 01 __ 03 02] +Name: , Id: _21, Ty: Aggregate, Value: +Name: , Id: _22, Ty: (u8, u16), Value: +Name: unit_variant, Id: _23, Ty: Choice, Value: [00 __ __ __ __ __ __ __] +Name: tuple_variant, Id: _24, Ty: Choice, Value: [01 0d 0f 0e __ __ __ __] +Name: struct_variant, Id: _25, Ty: Choice, Value: [02 01 __ __ 13 12 11 10] +Name: uninit_scalar, Id: _26, Ty: u32, Value: +Name: , Id: _27, Ty: (u8, &u8, usize, &Aggregate, &(u8, u16), &TupleAggregate, &[u8; 3], &Nested, &Choice, &Choice, &Choice), Value: +Name: , Id: _28, Ty: (u8, &u8, usize, &Aggregate, &(u8, u16), &TupleAggregate, &[u8; 3], &Nested, &Choice, &Choice, &Choice), Value: +Name: , Id: _29, Ty: u8, Value: +Name: , Id: _30, Ty: &u8, Value: +Name: , Id: _31, Ty: usize, Value: +Name: , Id: _32, Ty: &[u8], Value: +Name: , Id: _33, Ty: &Aggregate, Value: +Name: , Id: _34, Ty: &(u8, u16), Value: +Name: , Id: _35, Ty: &TupleAggregate, Value: +Name: , Id: _36, Ty: &[u8; 3], Value: +Name: , Id: _37, Ty: &Nested, Value: +Name: , Id: _38, Ty: &Choice, Value: +Name: , Id: _39, Ty: &Choice, Value: +Name: , Id: _40, Ty: &Choice, Value: +Name: , Id: _41, Ty: &[u8; 2], Value: {&_: &[u8; 2]} (priroda) Id: _0, Ty: (), Value: (priroda) Id: _4, Ty: std::boxed::Box, Value: (priroda) Id: _5, Ty: std::boxed::Box, Value: [{ALLOC_PTR}] @@ -34,5 +50,12 @@ Name: , Id: _25, Ty: &[u8; 2], Value: {&_: &[u8; 2]} (priroda) Id: _8, Ty: u8, Value: [33] (priroda) Id: _13, Ty: [u8; 2], Value: (priroda) Id: _15, Ty: Aggregate, Value: [34 12 2a __] +(priroda) Id: _17, Ty: (u8, u16), Value: [01 __ 03 02] +(priroda) Id: _18, Ty: TupleAggregate, Value: [06 05 04 __] +(priroda) Id: _19, Ty: [u8; 3], Value: [07 08 09] +(priroda) Id: _20, Ty: Nested, Value: [0c 0b 0a __ 01 __ 03 02] +(priroda) Id: _23, Ty: Choice, Value: [00 __ __ __ __ __ __ __] +(priroda) Id: _24, Ty: Choice, Value: [01 0d 0f 0e __ __ __ __] +(priroda) Id: _25, Ty: Choice, Value: [02 01 __ __ 13 12 11 10] (priroda) no local for this id (priroda) quitting From bc56612d1887edd857295e9fa2bedaa440eb724f Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Mon, 27 Jul 2026 05:36:39 +0000 Subject: [PATCH 02/23] Prepare for merging from rust-lang/rust This updates the rust-version file to dfbea5bc945a9d7ff017d3d4bfbd1af9295fe5b8. --- 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 25a5238f538ee..57e0ac6d84e12 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -390279b302ca98ae270f434100ae3730531d1246 +dfbea5bc945a9d7ff017d3d4bfbd1af9295fe5b8 From a3eac7e182ee7a60680c30b781307390f2ad40e8 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Mon, 27 Jul 2026 05:42:18 +0000 Subject: [PATCH 03/23] fmt --- src/tools/miri/src/shims/native_lib/trace/child.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tools/miri/src/shims/native_lib/trace/child.rs b/src/tools/miri/src/shims/native_lib/trace/child.rs index 0a049b4178722..d50d6ddc0416d 100644 --- a/src/tools/miri/src/shims/native_lib/trace/child.rs +++ b/src/tools/miri/src/shims/native_lib/trace/child.rs @@ -1,10 +1,10 @@ use std::cell::RefCell; -use std::ptr::NonNull; -use std::rc::Rc; -#[cfg(bootstrap)] -use std::panic::abort_unwind as abort_on_unwind; #[cfg(not(bootstrap))] use std::panic::abort_on_unwind; +#[cfg(bootstrap)] +use std::panic::abort_unwind as abort_on_unwind; +use std::ptr::NonNull; +use std::rc::Rc; use ipc_channel::{TryRecvError, ipc}; use nix::sys::{mman, ptrace, signal}; From 316b77bf46a77671d3e0fc3cfcb06c57da8f4d05 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Jul 2026 10:46:21 +0200 Subject: [PATCH 04/23] skip weak memory buffer handling when there is only one thread --- src/tools/miri/src/concurrency/data_race.rs | 4 ++-- src/tools/miri/src/concurrency/weak_memory.rs | 13 ++++++++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs index 1cdfb1d21b8cb..706dc1a19c78b 100644 --- a/src/tools/miri/src/concurrency/data_race.rs +++ b/src/tools/miri/src/concurrency/data_race.rs @@ -1674,11 +1674,11 @@ impl GlobalState { // We perform data race detection when there are more than 1 active thread // and we have not temporarily disabled race detection to perform something // data race free - fn race_detecting(&self) -> bool { + pub(super) fn race_detecting(&self) -> bool { self.multi_threaded.get() && !self.ongoing_action_data_race_free.get() } - pub fn ongoing_action_data_race_free(&self) -> bool { + pub(super) fn ongoing_action_data_race_free(&self) -> bool { self.ongoing_action_data_race_free.get() } diff --git a/src/tools/miri/src/concurrency/weak_memory.rs b/src/tools/miri/src/concurrency/weak_memory.rs index b3dbf1425047f..4838144d1d862 100644 --- a/src/tools/miri/src/concurrency/weak_memory.rs +++ b/src/tools/miri/src/concurrency/weak_memory.rs @@ -492,6 +492,8 @@ impl StoreElement { impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { + /// Update the store buffer after an RMW. + /// Does nothing if we are currently not detecting races (e.g. single-threaded mode). fn buffered_atomic_rmw( &mut self, new_val: Scalar, @@ -510,6 +512,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { data_race: GlobalDataRaceHandler::Vclocks(global), threads, .. }, ) = this.get_alloc_extra_mut(alloc_id)? + && global.race_detecting() { if atomic == AtomicRwOrd::SeqCst { global.sc_read(threads); @@ -531,6 +534,10 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(()) } + /// Perform a store buffer load. Returning `None` indicates a read of uninitialized memory. + /// Does nothing if we are currently not detecting races (e.g. single-threaded mode). + /// + /// `latest_in_mo` must be the most recent value according to the mo relation. /// The argument to `validate` is the synchronization clock of the memory that is being read, /// if we are reading from a store buffer element. fn buffered_atomic_read( @@ -542,7 +549,9 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx, Option> { let this = self.eval_context_ref(); 'fallback: { - if let Some(global) = this.machine.data_race.as_vclocks_ref() { + if let Some(global) = this.machine.data_race.as_vclocks_ref() + && global.race_detecting() + { let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr(), 0)?; if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.data_race.as_weak_memory_ref() @@ -582,6 +591,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Add the given write to the store buffer. (Does not change machine memory.) /// Must only be called after we determined that there is no data race or mixed-size race. + /// Does nothing if we are currently not detecting races (e.g. single-threaded mode). /// /// `init` says with which value to initialize the store buffer in case there wasn't a store /// buffer for this memory range before. `None` means the memory does not contain a valid @@ -606,6 +616,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { data_race: GlobalDataRaceHandler::Vclocks(global), threads, .. }, ) = this.get_alloc_extra_mut(alloc_id)? + && global.race_detecting() { if atomic == AtomicWriteOrd::SeqCst { global.sc_write(threads); From 83a423bc06636e37faa21596265abd85a47f1539 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Jul 2026 08:23:02 +0200 Subject: [PATCH 05/23] bless test-cargo-miri --- .../miri/test-cargo-miri/test.bin-target.stdout.ref | 5 +++-- .../miri/test-cargo-miri/test.default.stdout.ref | 6 +++--- .../miri/test-cargo-miri/test.filter.stdout.ref | 2 +- .../test-cargo-miri/test.multiple_targets.stdout.ref | 12 ++++++------ .../miri/test-cargo-miri/test.no-doc.stdout.ref | 6 +++--- .../miri/test-cargo-miri/test.workspace.stdout.ref | 6 +++--- 6 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/tools/miri/test-cargo-miri/test.bin-target.stdout.ref b/src/tools/miri/test-cargo-miri/test.bin-target.stdout.ref index 6f480259965b9..b281a863eb365 100644 --- a/src/tools/miri/test-cargo-miri/test.bin-target.stdout.ref +++ b/src/tools/miri/test-cargo-miri/test.bin-target.stdout.ref @@ -1,7 +1,8 @@ -running 2 tests +running 3 tests test test::dev_dependency ... ok test test::exported_symbol ... ok +test test::static_initializer_in_dep ... ok -test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME diff --git a/src/tools/miri/test-cargo-miri/test.default.stdout.ref b/src/tools/miri/test-cargo-miri/test.default.stdout.ref index ef092ef703bb8..deb7cd839f125 100644 --- a/src/tools/miri/test-cargo-miri/test.default.stdout.ref +++ b/src/tools/miri/test-cargo-miri/test.default.stdout.ref @@ -1,7 +1,7 @@ -running 2 tests -.. -test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME +running 3 tests +... +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME imported main diff --git a/src/tools/miri/test-cargo-miri/test.filter.stdout.ref b/src/tools/miri/test-cargo-miri/test.filter.stdout.ref index 071aa5691c1aa..a4d912e7a8d0a 100644 --- a/src/tools/miri/test-cargo-miri/test.filter.stdout.ref +++ b/src/tools/miri/test-cargo-miri/test.filter.stdout.ref @@ -1,7 +1,7 @@ running 0 tests -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out; finished in $TIME +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 3 filtered out; finished in $TIME imported main diff --git a/src/tools/miri/test-cargo-miri/test.multiple_targets.stdout.ref b/src/tools/miri/test-cargo-miri/test.multiple_targets.stdout.ref index 20139e9ffe621..b36fb3af66641 100644 --- a/src/tools/miri/test-cargo-miri/test.multiple_targets.stdout.ref +++ b/src/tools/miri/test-cargo-miri/test.multiple_targets.stdout.ref @@ -1,12 +1,12 @@ -running 2 tests -.. -test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME +running 3 tests +... +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME -running 2 tests -.. -test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME +running 3 tests +... +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME imported main imported main diff --git a/src/tools/miri/test-cargo-miri/test.no-doc.stdout.ref b/src/tools/miri/test-cargo-miri/test.no-doc.stdout.ref index 2ef124e4de8f7..769fbe6b24d53 100644 --- a/src/tools/miri/test-cargo-miri/test.no-doc.stdout.ref +++ b/src/tools/miri/test-cargo-miri/test.no-doc.stdout.ref @@ -1,7 +1,7 @@ -running 2 tests -.. -test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME +running 3 tests +... +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME imported main diff --git a/src/tools/miri/test-cargo-miri/test.workspace.stdout.ref b/src/tools/miri/test-cargo-miri/test.workspace.stdout.ref index c4884251774a3..c890af4bd974c 100644 --- a/src/tools/miri/test-cargo-miri/test.workspace.stdout.ref +++ b/src/tools/miri/test-cargo-miri/test.workspace.stdout.ref @@ -1,7 +1,7 @@ -running 2 tests -.. -test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME +running 3 tests +... +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME imported main From 47eb30f220ce632bcadbc65942b732fbe60e06cc Mon Sep 17 00:00:00 2001 From: Mohamed Ali Date: Fri, 24 Jul 2026 13:13:56 +0300 Subject: [PATCH 06/23] [Priroda] Add source-shaped value renderer plumbing Route local value rendering through a source-shaped renderer helper. At this step the helper still delegates leaves and unsupported shapes back to the existing raw byte renderer, so the behavioral changes can land in focused follow-up commits. --- src/tools/miri/priroda/src/main.rs | 43 ++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/src/tools/miri/priroda/src/main.rs b/src/tools/miri/priroda/src/main.rs index e748ae7340aa2..6c491470ed524 100644 --- a/src/tools/miri/priroda/src/main.rs +++ b/src/tools/miri/priroda/src/main.rs @@ -505,6 +505,45 @@ impl<'tcx> PrirodaContext<'tcx> { interp_ok(format!("[{}]", rendered.join(" "))) } + /// Render an evaluated operand using Rust-source-shaped containers with raw leaves. + /// + /// The operand is produced from live interpreter state, usually via `local_to_op` + /// for a whole MIR local or `eval_place_to_op` for a projected debug-info place. + /// + /// This intentionally does not call user `Debug` / `Display`, and it does not + /// try to make every scalar leaf pretty yet. Unsupported cases and leaf values + /// fall back to `render_op`, preserving the old raw byte/provenance renderer. + /// + /// FIXME: teach the leaf renderer about simple Rust scalars (`bool`, integers, + /// chars, raw pointers/references) once the source-shaped container output is + /// stable enough to stop depending on byte dumps for every field. + /// + /// FIXME: decide how much dereferencing belongs in this renderer. References + /// currently stay as raw pointer leaves; following them may belong in the + /// existing `follow` command instead of automatic local rendering. + fn render_source_shaped_op(&self, op: OpTy<'tcx>) -> String { + self.render_source_shaped_op_inner(op, 0) + } + + /// Recursive worker for `render_source_shaped_op`. + /// + /// The depth limit keeps cyclic/reference-heavy values from making debugger + /// output explode once more container kinds are added. At the limit, the raw + /// renderer remains the ground truth. + /// + /// FIXME: replace this fixed recursion limit with a value-size/output-budget + /// policy so large acyclic values and deeply nested values degrade more + /// predictably. + fn render_source_shaped_op_inner(&self, op: OpTy<'tcx>, depth: usize) -> String { + const MAX_SOURCE_SHAPE_DEPTH: usize = 8; + + if depth >= MAX_SOURCE_SHAPE_DEPTH { + return self.render_op(op); + } + + self.render_op(op) + } + /// Render an evaluated operand using the same raw representation for /// whole locals and projected MIR places. fn render_op(&self, op: OpTy<'tcx>) -> String { @@ -613,7 +652,7 @@ impl<'tcx> PrirodaContext<'tcx> { .ecx .local_to_op(local, None) .expect("this error can only occur in CTFE on generic code"); - local_desc.value = self.render_op(op); + local_desc.value = self.render_source_shaped_op(op); } }; @@ -682,7 +721,7 @@ impl<'tcx> PrirodaContext<'tcx> { let value = self .ecx .eval_place_to_op(*place, None) - .map(|op| self.render_op(op)) + .map(|op| self.render_source_shaped_op(op)) .unwrap_or_else(|err| { format!("", interpret::format_interp_error(err)) }); From 7edd27fe86a9bbe31db1c6567e32fc0ff4cdde16 Mon Sep 17 00:00:00 2001 From: Mohamed Ali Date: Fri, 24 Jul 2026 13:15:17 +0300 Subject: [PATCH 07/23] [Priroda] Render source-shaped struct values Render struct and struct-like ADT operands using their source field names. Fields are projected from the operand and each leaf still uses the existing raw renderer, producing output such as `Point { x: [..], y: [..] }` without relying on user Debug or Display implementations. --- src/tools/miri/priroda/src/main.rs | 61 ++++++++++++++++++- .../tests/ui/locals_access_field.stdout | 4 +- .../tests/ui/locals_corpus_async.stdout | 2 +- .../tests/ui/locals_pointer_rendering.stdout | 12 ++-- .../ui/locals_projected_mplace_size.stdout | 4 +- .../tests/ui/locals_source_shapes.stdout | 24 ++++---- .../tests/ui/locals_value_shapes.stdout | 20 +++--- .../tests/ui/locals_wildcard_pointer.stdout | 4 +- 8 files changed, 93 insertions(+), 38 deletions(-) diff --git a/src/tools/miri/priroda/src/main.rs b/src/tools/miri/priroda/src/main.rs index 6c491470ed524..2d4982959639c 100644 --- a/src/tools/miri/priroda/src/main.rs +++ b/src/tools/miri/priroda/src/main.rs @@ -23,13 +23,14 @@ use std::path::PathBuf; use miri::Immediate::Uninit; use miri::{interpret, *}; -use rustc_abi::Size; +use rustc_abi::{FIRST_VARIANT, FieldIdx, Size}; use rustc_driver::Compilation; use rustc_hir::attrs::CrateType; +use rustc_hir::def::CtorKind; use rustc_interface::interface; use rustc_middle::mir::interpret::AllocId; use rustc_middle::mir::{self, Local, ProjectionElem, VarDebugInfoContents, VarDebugInfoFragment}; -use rustc_middle::ty::{TyCtxt, TyKind}; +use rustc_middle::ty::{self, TyCtxt, TyKind}; use rustc_session::EarlyDiagCtxt; use rustc_session::config::ErrorOutputType; use rustc_span::source_map::SourceMap; @@ -541,7 +542,61 @@ impl<'tcx> PrirodaContext<'tcx> { return self.render_op(op); } - self.render_op(op) + match op.layout.ty.kind() { + // Empty enums have no active variant to format. Unions do not record + // which field is currently active, so choosing one would be misleading. + // + // FIXME: support unions only with an explicit user-selected field or + // another source of active-field information. Guessing from layout + // bytes would make debugger output look more certain than it is. + ty::Adt(def, _) if def.variants().is_empty() || def.is_union() => self.render_op(op), + + ty::Adt(def, _) if def.is_struct() => { + let variant_idx = FIRST_VARIANT; + let variant_def = &def.variants()[variant_idx]; + let name = variant_def.name.to_string(); + + let mut fields = Vec::with_capacity(variant_def.fields.len()); + for i in 0..variant_def.fields.len() { + let field_idx = FieldIdx::from_usize(i); + // `project_field` avoids manual offset math and works for both + // immediate and memory-backed operands through `Projectable`. + let field_op = match self.ecx.project_field(&op, field_idx).discard_err() { + Some(field_op) => field_op, + // FIXME: preserve the successfully rendered fields and + // mark only this field as unavailable once the value model + // can represent partial render failures. + None => return self.render_op(op), + }; + fields.push(self.render_source_shaped_op_inner(field_op, depth + 1)); + } + + // Match Rust constructor spelling: + // - `Const`: unit structs, e.g. `UnitStruct` + // - `Fn`: tuple structs, e.g. `Pair(a, b)` or `EmptyTuple()` + // - `None`: braced structs, including the empty `{}` case + match variant_def.ctor_kind() { + Some(CtorKind::Const) => name, + Some(CtorKind::Fn) => format!("{name}({})", fields.join(", ")), + None if fields.is_empty() => format!("{name} {{}}"), + None => { + let fields = variant_def + .fields + .iter() + .zip(fields) + .map(|(field_def, value)| format!("{}: {value}", field_def.name)) + .collect::>() + .join(", "); + format!("{name} {{ {fields} }}") + } + } + } + + // FIXME: consider source-shaped special cases for strings, closures, + // generators/coroutines, trait objects, and SIMD/vector-like types. + // Until then these stay on the raw renderer path. + _ => self.render_op(op), + } } /// Render an evaluated operand using the same raw representation for diff --git a/src/tools/miri/priroda/tests/ui/locals_access_field.stdout b/src/tools/miri/priroda/tests/ui/locals_access_field.stdout index 65a40a5ab584d..8f54636373a2a 100644 --- a/src/tools/miri/priroda/tests/ui/locals_access_field.stdout +++ b/src/tools/miri/priroda/tests/ui/locals_access_field.stdout @@ -2,11 +2,11 @@ (priroda) Hit breakpoint {MANIFEST_DIR}/tests/ui/locals_access_field.rs:14 (priroda) Name: , Id: _0, Ty: (), Value: -Name: extraslice, Id: _1, Ty: ExtraSlice<'_>, Value: [{ALLOC_PTR} 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __] +Name: extraslice, Id: _1, Ty: ExtraSlice<'_>, Value: ExtraSlice { _slice: [{ALLOC_PTR} 00 00 00 00 00 00 00 00], _extra: [00 00 00 00] } Name: _slice, Id: _2, Ty: &[u8], Value: (pointer to {ALLOC_PTR}, 0x0000000000000000): &[u8] Name: _extra, Id: _3, Ty: u32, Value: 0_u32 (priroda) Id: _0, Ty: (), Value: -(priroda) Id: _1, Ty: ExtraSlice<'_>, Value: [{ALLOC_PTR} 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __] +(priroda) Id: _1, Ty: ExtraSlice<'_>, Value: ExtraSlice { _slice: [{ALLOC_PTR} 00 00 00 00 00 00 00 00], _extra: [00 00 00 00] } (priroda) Id: _2, Ty: &[u8], Value: (pointer to {ALLOC_PTR}, 0x0000000000000000): &[u8] (priroda) Id: _3, Ty: u32, Value: 0_u32 (priroda) no local for this id diff --git a/src/tools/miri/priroda/tests/ui/locals_corpus_async.stdout b/src/tools/miri/priroda/tests/ui/locals_corpus_async.stdout index 6ccfbc997c590..85fdc45566f2a 100644 --- a/src/tools/miri/priroda/tests/ui/locals_corpus_async.stdout +++ b/src/tools/miri/priroda/tests/ui/locals_corpus_async.stdout @@ -13,7 +13,7 @@ Name: second, Id: _1.1, Ty: i32, Value: 6_i32 (priroda) Hit breakpoint {MANIFEST_DIR}/tests/ui/locals_corpus_async.rs:45 (priroda) Name: , Id: _0, Ty: (), Value: -Name: , Id: _1, Ty: S, Value: {transmute(0x40a00000): S} +Name: , Id: _1, Ty: S, Value: S { x: 5f32 } Name: x, Id: _1.0, Ty: f32, Value: 5f32 (priroda) Hit breakpoint {MANIFEST_DIR}/tests/ui/locals_corpus_async.rs:55 diff --git a/src/tools/miri/priroda/tests/ui/locals_pointer_rendering.stdout b/src/tools/miri/priroda/tests/ui/locals_pointer_rendering.stdout index f26a06e16ae0c..27d37e4940acb 100644 --- a/src/tools/miri/priroda/tests/ui/locals_pointer_rendering.stdout +++ b/src/tools/miri/priroda/tests/ui/locals_pointer_rendering.stdout @@ -3,30 +3,30 @@ {MANIFEST_DIR}/tests/ui/locals_pointer_rendering.rs:59 (priroda) Name: , Id: _0, Ty: (), Value: Name: target, Id: _1, Ty: [u8; 2], Value: [0a 14] -Name: pointer_at_offset0, Id: _2, Ty: PointerAtOffset0<'_>, Value: [{ALLOC_PTR}] +Name: pointer_at_offset0, Id: _2, Ty: PointerAtOffset0<'_>, Value: PointerAtOffset0 { ptr: [{ALLOC_PTR}] } Name: , Id: _3, Ty: &u8, Value: Name: , Id: _4, Ty: &u8, Value: Name: , Id: _5, Ty: usize, Value: Name: , Id: _6, Ty: bool, Value: true -Name: pointer_after_bytes, Id: _7, Ty: PointerAfterBytes<'_>, Value: [01 02 03 __ __ __ __ __ {ALLOC_PTR}] +Name: pointer_after_bytes, Id: _7, Ty: PointerAfterBytes<'_>, Value: PointerAfterBytes { bytes: [01 02 03], ptr: [{ALLOC_PTR}] } Name: , Id: _8, Ty: [u8; 3], Value: Name: , Id: _9, Ty: &u8, Value: Name: , Id: _10, Ty: &u8, Value: Name: , Id: _11, Ty: usize, Value: Name: , Id: _12, Ty: bool, Value: true -Name: pointer_at_end, Id: _13, Ty: PointerAtEnd<'_>, Value: [04 __ __ __ __ __ __ __ {ALLOC_PTR}] +Name: pointer_at_end, Id: _13, Ty: PointerAtEnd<'_>, Value: PointerAtEnd { byte: [04], ptr: [{ALLOC_PTR}] } Name: , Id: _14, Ty: &u8, Value: Name: , Id: _15, Ty: &u8, Value: Name: , Id: _16, Ty: usize, Value: Name: , Id: _17, Ty: bool, Value: true -Name: uninit_around_pointer, Id: _18, Ty: UninitAroundPointer<'_>, Value: [__ __ __ __ __ __ __ __ {ALLOC_PTR} __ __ __ __ __ __ __ __] +Name: uninit_around_pointer, Id: _18, Ty: UninitAroundPointer<'_>, Value: UninitAroundPointer { before: [__ __], ptr: [{ALLOC_PTR}], after: [__ __] } Name: , Id: _19, Ty: std::mem::MaybeUninit<[u8; 2]>, Value: Name: , Id: _20, Ty: &u8, Value: Name: , Id: _21, Ty: &u8, Value: Name: , Id: _22, Ty: usize, Value: Name: , Id: _23, Ty: bool, Value: true Name: , Id: _24, Ty: std::mem::MaybeUninit<[u8; 2]>, Value: -Name: integer_and_pointer, Id: _25, Ty: IntegerAndPointer<'_>, Value: [11 22 33 44 __ __ __ __ {ALLOC_PTR}] +Name: integer_and_pointer, Id: _25, Ty: IntegerAndPointer<'_>, Value: IntegerAndPointer { integer: [11 22 33 44], ptr: [{ALLOC_PTR}] } Name: , Id: _26, Ty: &u8, Value: Name: , Id: _27, Ty: &u8, Value: Name: , Id: _28, Ty: usize, Value: @@ -52,5 +52,5 @@ Name: , Id: _47, Ty: &UninitAroundPointer<'_>, Value: Name: , Id: _48, Ty: &IntegerAndPointer<'_>, Value: Name: , Id: _49, Ty: &*const u8, Value: Name: , Id: _50, Ty: &[u8; 1], Value: -(priroda) Id: _2, Ty: PointerAtOffset0<'_>, Value: [{ALLOC_PTR}] +(priroda) Id: _2, Ty: PointerAtOffset0<'_>, Value: PointerAtOffset0 { ptr: [{ALLOC_PTR}] } (priroda) quitting diff --git a/src/tools/miri/priroda/tests/ui/locals_projected_mplace_size.stdout b/src/tools/miri/priroda/tests/ui/locals_projected_mplace_size.stdout index a2111bed511aa..150385de95b9a 100644 --- a/src/tools/miri/priroda/tests/ui/locals_projected_mplace_size.stdout +++ b/src/tools/miri/priroda/tests/ui/locals_projected_mplace_size.stdout @@ -2,9 +2,9 @@ (priroda) Hit breakpoint {MANIFEST_DIR}/tests/ui/locals_projected_mplace_size.rs:36 (priroda) Name: , Id: _0, Ty: (), Value: -Name: , Id: _1, Ty: Envelope, Value: [aa __ __ __ 22 11 33 __ 77 66 55 44 88 __ __ __ 00 ff ee dd cc bb aa 99 34 12 __ __ __ __ __ __] +Name: , Id: _1, Ty: Envelope, Value: Envelope { prefix: [aa], target: Payload { a: [22 11], b: [33], c: [77 66 55 44], d: [88] }, trailer: [00 ff ee dd cc bb aa 99], checksum: [34 12] } Name: prefix, Id: _1.0, Ty: u8, Value: [aa] -Name: target, Id: _1.1, Ty: Payload, Value: [22 11 33 __ 77 66 55 44 88 __ __ __] +Name: target, Id: _1.1, Ty: Payload, Value: Payload { a: [22 11], b: [33], c: [77 66 55 44], d: [88] } Name: trailer, Id: _1.2, Ty: u64, Value: [00 ff ee dd cc bb aa 99] Name: checksum, Id: _1.3, Ty: u16, Value: [34 12] (priroda) quitting diff --git a/src/tools/miri/priroda/tests/ui/locals_source_shapes.stdout b/src/tools/miri/priroda/tests/ui/locals_source_shapes.stdout index 7482832a65c6b..05cc75d9ccd32 100644 --- a/src/tools/miri/priroda/tests/ui/locals_source_shapes.stdout +++ b/src/tools/miri/priroda/tests/ui/locals_source_shapes.stdout @@ -2,12 +2,12 @@ (priroda) Hit breakpoint {MANIFEST_DIR}/tests/ui/locals_source_shapes.rs:71 (priroda) Name: , Id: _0, Ty: (), Value: -Name: named, Id: _1, Ty: Named, Value: [02 03 01 __] -Name: empty_braced, Id: _2, Ty: EmptyBraced, Value: [] -Name: unit_struct, Id: _3, Ty: UnitStruct, Value: [] -Name: tuple_struct, Id: _4, Ty: TupleStruct, Value: [05 06 04 __] -Name: single_tuple_struct, Id: _5, Ty: SingleTupleStruct, Value: [07] -Name: zero_tuple_struct, Id: _6, Ty: ZeroTupleStruct, Value: [] +Name: named, Id: _1, Ty: Named, Value: Named { a: [01], b: [02 03] } +Name: empty_braced, Id: _2, Ty: EmptyBraced, Value: EmptyBraced {} +Name: unit_struct, Id: _3, Ty: UnitStruct, Value: UnitStruct +Name: tuple_struct, Id: _4, Ty: TupleStruct, Value: TupleStruct([04], [05 06]) +Name: single_tuple_struct, Id: _5, Ty: SingleTupleStruct, Value: SingleTupleStruct([07]) +Name: zero_tuple_struct, Id: _6, Ty: ZeroTupleStruct, Value: ZeroTupleStruct() Name: tuple_zero, Id: _7, Ty: (), Value: [] Name: tuple_one, Id: _8, Ty: (u8,), Value: [08] Name: tuple_many, Id: _9, Ty: (u8, u16), Value: [09 __ 0a 0b] @@ -41,12 +41,12 @@ Name: , Id: _36, Ty: &Variants, Value: Name: , Id: _37, Ty: &Variants, Value: Name: , Id: _38, Ty: &RawUnion, Value: Name: , Id: _39, Ty: u8, Value: -(priroda) Id: _1, Ty: Named, Value: [02 03 01 __] -(priroda) Id: _2, Ty: EmptyBraced, Value: [] -(priroda) Id: _3, Ty: UnitStruct, Value: [] -(priroda) Id: _4, Ty: TupleStruct, Value: [05 06 04 __] -(priroda) Id: _5, Ty: SingleTupleStruct, Value: [07] -(priroda) Id: _6, Ty: ZeroTupleStruct, Value: [] +(priroda) Id: _1, Ty: Named, Value: Named { a: [01], b: [02 03] } +(priroda) Id: _2, Ty: EmptyBraced, Value: EmptyBraced {} +(priroda) Id: _3, Ty: UnitStruct, Value: UnitStruct +(priroda) Id: _4, Ty: TupleStruct, Value: TupleStruct([04], [05 06]) +(priroda) Id: _5, Ty: SingleTupleStruct, Value: SingleTupleStruct([07]) +(priroda) Id: _6, Ty: ZeroTupleStruct, Value: ZeroTupleStruct() (priroda) Id: _7, Ty: (), Value: [] (priroda) Id: _8, Ty: (u8,), Value: [08] (priroda) Id: _9, Ty: (u8, u16), Value: [09 __ 0a 0b] diff --git a/src/tools/miri/priroda/tests/ui/locals_value_shapes.stdout b/src/tools/miri/priroda/tests/ui/locals_value_shapes.stdout index b9f01f637c67e..609019bd4a59a 100644 --- a/src/tools/miri/priroda/tests/ui/locals_value_shapes.stdout +++ b/src/tools/miri/priroda/tests/ui/locals_value_shapes.stdout @@ -2,11 +2,11 @@ (priroda) Hit breakpoint {MANIFEST_DIR}/tests/ui/locals_value_shapes.rs:49 (priroda) Name: , Id: _0, Ty: (), Value: -Name: dead_box, Id: _1, Ty: std::boxed::Box, Value: [{ALLOC_PTR}] -Name: consumed, Id: _2, Ty: std::boxed::Box, Value: [{ALLOC_PTR}] +Name: dead_box, Id: _1, Ty: std::boxed::Box, Value: Box(Unique { pointer: NonNull { pointer: [{ALLOC_PTR}] }, _marker: PhantomData }, Global) +Name: consumed, Id: _2, Ty: std::boxed::Box, Value: Box(Unique { pointer: NonNull { pointer: [{ALLOC_PTR}] }, _marker: PhantomData }, Global) Name: , Id: _3, Ty: (), Value: Name: , Id: _4, Ty: std::boxed::Box, Value: -Name: pointed_box, Id: _5, Ty: std::boxed::Box, Value: [{ALLOC_PTR}] +Name: pointed_box, Id: _5, Ty: std::boxed::Box, Value: Box(Unique { pointer: NonNull { pointer: [{ALLOC_PTR}] }, _marker: PhantomData }, Global) Name: pointer_box, Id: _6, Ty: &std::boxed::Box, Value: {&_: &std::boxed::Box} Name: scalar, Id: _7, Ty: u8, Value: 42_u8 Name: pointed, Id: _8, Ty: u8, Value: [33] @@ -16,12 +16,12 @@ Name: , Id: _11, Ty: &[u8], Value: (pointer to {ALLOC_PTR}, 0x000000000000 Name: , Id: _12, Ty: &[u8; 2], Value: Name: , Id: _13, Ty: [u8; 2], Value: Name: , Id: _14, Ty: std::ops::RangeFull, Value: -Name: mplace, Id: _15, Ty: Aggregate, Value: [34 12 2a __] +Name: mplace, Id: _15, Ty: Aggregate, Value: Aggregate { byte: [2a], word: [34 12] } Name: , Id: _16, Ty: u8, Value: Name: tuple, Id: _17, Ty: (u8, u16), Value: [01 __ 03 02] -Name: tuple_struct, Id: _18, Ty: TupleAggregate, Value: [06 05 04 __] +Name: tuple_struct, Id: _18, Ty: TupleAggregate, Value: TupleAggregate([04], [06 05]) Name: array, Id: _19, Ty: [u8; 3], Value: [07 08 09] -Name: nested, Id: _20, Ty: Nested, Value: [0c 0b 0a __ 01 __ 03 02] +Name: nested, Id: _20, Ty: Nested, Value: Nested { aggregate: Aggregate { byte: [0a], word: [0c 0b] }, tuple: [01 __ 03 02] } Name: , Id: _21, Ty: Aggregate, Value: Name: , Id: _22, Ty: (u8, u16), Value: Name: unit_variant, Id: _23, Ty: Choice, Value: [00 __ __ __ __ __ __ __] @@ -45,15 +45,15 @@ Name: , Id: _40, Ty: &Choice, Value: Name: , Id: _41, Ty: &[u8; 2], Value: {&_: &[u8; 2]} (priroda) Id: _0, Ty: (), Value: (priroda) Id: _4, Ty: std::boxed::Box, Value: -(priroda) Id: _5, Ty: std::boxed::Box, Value: [{ALLOC_PTR}] +(priroda) Id: _5, Ty: std::boxed::Box, Value: Box(Unique { pointer: NonNull { pointer: [{ALLOC_PTR}] }, _marker: PhantomData }, Global) (priroda) Id: _7, Ty: u8, Value: 42_u8 (priroda) Id: _8, Ty: u8, Value: [33] (priroda) Id: _13, Ty: [u8; 2], Value: -(priroda) Id: _15, Ty: Aggregate, Value: [34 12 2a __] +(priroda) Id: _15, Ty: Aggregate, Value: Aggregate { byte: [2a], word: [34 12] } (priroda) Id: _17, Ty: (u8, u16), Value: [01 __ 03 02] -(priroda) Id: _18, Ty: TupleAggregate, Value: [06 05 04 __] +(priroda) Id: _18, Ty: TupleAggregate, Value: TupleAggregate([04], [06 05]) (priroda) Id: _19, Ty: [u8; 3], Value: [07 08 09] -(priroda) Id: _20, Ty: Nested, Value: [0c 0b 0a __ 01 __ 03 02] +(priroda) Id: _20, Ty: Nested, Value: Nested { aggregate: Aggregate { byte: [0a], word: [0c 0b] }, tuple: [01 __ 03 02] } (priroda) Id: _23, Ty: Choice, Value: [00 __ __ __ __ __ __ __] (priroda) Id: _24, Ty: Choice, Value: [01 0d 0f 0e __ __ __ __] (priroda) Id: _25, Ty: Choice, Value: [02 01 __ __ 13 12 11 10] diff --git a/src/tools/miri/priroda/tests/ui/locals_wildcard_pointer.stdout b/src/tools/miri/priroda/tests/ui/locals_wildcard_pointer.stdout index 866c549f49a46..43bccfb10e4a3 100644 --- a/src/tools/miri/priroda/tests/ui/locals_wildcard_pointer.stdout +++ b/src/tools/miri/priroda/tests/ui/locals_wildcard_pointer.stdout @@ -3,9 +3,9 @@ {MANIFEST_DIR}/tests/ui/locals_wildcard_pointer.rs:15 (priroda) Name: , Id: _0, Ty: (), Value: Name: ptr, Id: _1, Ty: *const u8, Value: {&_: *const u8} -Name: wildcard, Id: _2, Ty: WildcardPointer, Value: [0x1234[wildcard]] +Name: wildcard, Id: _2, Ty: WildcardPointer, Value: WildcardPointer { ptr: [0x1234[wildcard]] } Name: , Id: _3, Ty: *const u8, Value: Name: , Id: _4, Ty: &WildcardPointer, Value: Name: , Id: _5, Ty: &WildcardPointer, Value: -(priroda) Id: _2, Ty: WildcardPointer, Value: [0x1234[wildcard]] +(priroda) Id: _2, Ty: WildcardPointer, Value: WildcardPointer { ptr: [0x1234[wildcard]] } (priroda) quitting From 543afd70b9e325e37bba8e52ce83252b61f95ced Mon Sep 17 00:00:00 2001 From: Mohamed Ali Date: Fri, 24 Jul 2026 13:16:00 +0300 Subject: [PATCH 08/23] [Priroda] Render source-shaped enum values Extend source-shaped ADT rendering to enum operands. The renderer reads the runtime discriminant, downcasts to the active variant, and then renders the payload fields with the same raw-leaf fallback used for struct fields. Unit, tuple, and struct variants keep their Rust-like spelling. --- src/tools/miri/priroda/src/main.rs | 43 ++++++++++++++++--- .../tests/ui/locals_corpus_async.stdout | 4 +- .../tests/ui/locals_source_shapes.stdout | 20 ++++----- .../tests/ui/locals_value_shapes.stdout | 12 +++--- 4 files changed, 54 insertions(+), 25 deletions(-) diff --git a/src/tools/miri/priroda/src/main.rs b/src/tools/miri/priroda/src/main.rs index 2d4982959639c..9799888a9804c 100644 --- a/src/tools/miri/priroda/src/main.rs +++ b/src/tools/miri/priroda/src/main.rs @@ -551,17 +551,46 @@ impl<'tcx> PrirodaContext<'tcx> { // bytes would make debugger output look more certain than it is. ty::Adt(def, _) if def.variants().is_empty() || def.is_union() => self.render_op(op), - ty::Adt(def, _) if def.is_struct() => { - let variant_idx = FIRST_VARIANT; + ty::Adt(def, _) => { + // Enums need their runtime discriminant and a downcasted layout + // view before fields can be projected. Structs use their sole + // variant directly. Keep the display name tied to the same choice. + let (variant_idx, down, name) = if def.is_enum() { + let variant_idx = match self.ecx.read_discriminant(&op).discard_err() { + Some(variant_idx) => variant_idx, + // FIXME: expose this as an explicit render error when + // Priroda grows structured value states. Falling back to + // bytes keeps today's UI usable but hides why the enum + // could not be source-shaped. + None => return self.render_op(op), + }; + let down = match self.ecx.project_downcast(&op, variant_idx).discard_err() { + Some(down) => down, + // FIXME: distinguish invalid/uninitialized discriminants + // from projection bugs in the rendered output once locals + // can carry structured diagnostics. + None => return self.render_op(op), + }; + let variant_def = &def.variants()[variant_idx]; + ( + variant_idx, + down, + format!("{}::{}", self.ecx.tcx.item_name(def.did()), variant_def.name), + ) + } else { + let variant_idx = FIRST_VARIANT; + let variant_def = &def.variants()[variant_idx]; + (variant_idx, op.clone(), variant_def.name.to_string()) + }; + let variant_def = &def.variants()[variant_idx]; - let name = variant_def.name.to_string(); let mut fields = Vec::with_capacity(variant_def.fields.len()); for i in 0..variant_def.fields.len() { let field_idx = FieldIdx::from_usize(i); // `project_field` avoids manual offset math and works for both // immediate and memory-backed operands through `Projectable`. - let field_op = match self.ecx.project_field(&op, field_idx).discard_err() { + let field_op = match self.ecx.project_field(&down, field_idx).discard_err() { Some(field_op) => field_op, // FIXME: preserve the successfully rendered fields and // mark only this field as unavailable once the value model @@ -572,9 +601,9 @@ impl<'tcx> PrirodaContext<'tcx> { } // Match Rust constructor spelling: - // - `Const`: unit structs, e.g. `UnitStruct` - // - `Fn`: tuple structs, e.g. `Pair(a, b)` or `EmptyTuple()` - // - `None`: braced structs, including the empty `{}` case + // - `Const`: unit structs/variants, e.g. `UnitStruct`, `Enum::Unit` + // - `Fn`: tuple structs/variants, e.g. `Pair(a, b)` or `EmptyTuple()` + // - `None`: braced structs/variants, including the empty `{}` case match variant_def.ctor_kind() { Some(CtorKind::Const) => name, Some(CtorKind::Fn) => format!("{name}({})", fields.join(", ")), diff --git a/src/tools/miri/priroda/tests/ui/locals_corpus_async.stdout b/src/tools/miri/priroda/tests/ui/locals_corpus_async.stdout index 85fdc45566f2a..2d39662a81ab5 100644 --- a/src/tools/miri/priroda/tests/ui/locals_corpus_async.stdout +++ b/src/tools/miri/priroda/tests/ui/locals_corpus_async.stdout @@ -18,12 +18,12 @@ Name: x, Id: _1.0, Ty: f32, Value: 5f32 (priroda) Hit breakpoint {MANIFEST_DIR}/tests/ui/locals_corpus_async.rs:55 (priroda) Name: , Id: _0, Ty: (), Value: -Name: , Id: _1, Ty: std::option::Option, Value: [01 00 00 00 05 00 00 00] +Name: , Id: _1, Ty: std::option::Option, Value: Option::Some([05 00 00 00]) Name: inner, Id: _1 as variant#1.0, Ty: i32, Value: [05 00 00 00] (priroda) Hit breakpoint {MANIFEST_DIR}/tests/ui/locals_corpus_async.rs:66 (priroda) Name: , Id: _0, Ty: (), Value: -Name: , Id: _1, Ty: std::option::Option<&i32>, Value: [{ALLOC_PTR}] +Name: , Id: _1, Ty: std::option::Option<&i32>, Value: Option::Some([{ALLOC_PTR}]) Name: pointer, Id: _1 as variant#1.0, Ty: &i32, Value: [{ALLOC_PTR}] Name: deref, Id: _1 as variant#1.0.*, Ty: i32, Value: [05 00 00 00] (priroda) Allocation alloc2+0: [05 00 00 00] diff --git a/src/tools/miri/priroda/tests/ui/locals_source_shapes.stdout b/src/tools/miri/priroda/tests/ui/locals_source_shapes.stdout index 05cc75d9ccd32..5499312744ca3 100644 --- a/src/tools/miri/priroda/tests/ui/locals_source_shapes.stdout +++ b/src/tools/miri/priroda/tests/ui/locals_source_shapes.stdout @@ -14,11 +14,11 @@ Name: tuple_many, Id: _9, Ty: (u8, u16), Value: [09 __ 0a 0b] Name: array_zero, Id: _10, Ty: [u8; 0], Value: [] Name: array_one, Id: _11, Ty: [u8; 1], Value: [0c] Name: array_many, Id: _12, Ty: [u8; 3], Value: [0d 0e 0f] -Name: variant_unit, Id: _13, Ty: Variants, Value: [00 __ __ __ __ __ __ __] -Name: variant_tuple, Id: _14, Ty: Variants, Value: [01 10 11 12 __ __ __ __] -Name: variant_single_tuple, Id: _15, Ty: Variants, Value: [02 13 __ __ __ __ __ __] -Name: variant_struct, Id: _16, Ty: Variants, Value: [03 00 __ __ 14 15 16 17] -Name: variant_empty_struct, Id: _17, Ty: Variants, Value: [04 __ __ __ __ __ __ __] +Name: variant_unit, Id: _13, Ty: Variants, Value: Variants::Unit +Name: variant_tuple, Id: _14, Ty: Variants, Value: Variants::Tuple([10], [11 12]) +Name: variant_single_tuple, Id: _15, Ty: Variants, Value: Variants::SingleTuple([13]) +Name: variant_struct, Id: _16, Ty: Variants, Value: Variants::Struct { n: [14 15 16 17], ok: [00] } +Name: variant_empty_struct, Id: _17, Ty: Variants, Value: Variants::EmptyStruct {} Name: raw_union, Id: _18, Ty: RawUnion, Value: [18 19] Name: , Id: _19, Ty: (&Named, &EmptyBraced, &UnitStruct, &TupleStruct, &SingleTupleStruct, &ZeroTupleStruct, &(), &(u8,), &(u8, u16), &[u8; 0], &[u8; 1], &[u8; 3], &Variants, &Variants, &Variants, &Variants, &Variants, &RawUnion), Value: Name: , Id: _20, Ty: (&Named, &EmptyBraced, &UnitStruct, &TupleStruct, &SingleTupleStruct, &ZeroTupleStruct, &(), &(u8,), &(u8, u16), &[u8; 0], &[u8; 1], &[u8; 3], &Variants, &Variants, &Variants, &Variants, &Variants, &RawUnion), Value: @@ -53,10 +53,10 @@ Name: , Id: _39, Ty: u8, Value: (priroda) Id: _10, Ty: [u8; 0], Value: [] (priroda) Id: _11, Ty: [u8; 1], Value: [0c] (priroda) Id: _12, Ty: [u8; 3], Value: [0d 0e 0f] -(priroda) Id: _13, Ty: Variants, Value: [00 __ __ __ __ __ __ __] -(priroda) Id: _14, Ty: Variants, Value: [01 10 11 12 __ __ __ __] -(priroda) Id: _15, Ty: Variants, Value: [02 13 __ __ __ __ __ __] -(priroda) Id: _16, Ty: Variants, Value: [03 00 __ __ 14 15 16 17] -(priroda) Id: _17, Ty: Variants, Value: [04 __ __ __ __ __ __ __] +(priroda) Id: _13, Ty: Variants, Value: Variants::Unit +(priroda) Id: _14, Ty: Variants, Value: Variants::Tuple([10], [11 12]) +(priroda) Id: _15, Ty: Variants, Value: Variants::SingleTuple([13]) +(priroda) Id: _16, Ty: Variants, Value: Variants::Struct { n: [14 15 16 17], ok: [00] } +(priroda) Id: _17, Ty: Variants, Value: Variants::EmptyStruct {} (priroda) Id: _18, Ty: RawUnion, Value: [18 19] (priroda) quitting diff --git a/src/tools/miri/priroda/tests/ui/locals_value_shapes.stdout b/src/tools/miri/priroda/tests/ui/locals_value_shapes.stdout index 609019bd4a59a..20b8d670dc124 100644 --- a/src/tools/miri/priroda/tests/ui/locals_value_shapes.stdout +++ b/src/tools/miri/priroda/tests/ui/locals_value_shapes.stdout @@ -24,9 +24,9 @@ Name: array, Id: _19, Ty: [u8; 3], Value: [07 08 09] Name: nested, Id: _20, Ty: Nested, Value: Nested { aggregate: Aggregate { byte: [0a], word: [0c 0b] }, tuple: [01 __ 03 02] } Name: , Id: _21, Ty: Aggregate, Value: Name: , Id: _22, Ty: (u8, u16), Value: -Name: unit_variant, Id: _23, Ty: Choice, Value: [00 __ __ __ __ __ __ __] -Name: tuple_variant, Id: _24, Ty: Choice, Value: [01 0d 0f 0e __ __ __ __] -Name: struct_variant, Id: _25, Ty: Choice, Value: [02 01 __ __ 13 12 11 10] +Name: unit_variant, Id: _23, Ty: Choice, Value: Choice::Unit +Name: tuple_variant, Id: _24, Ty: Choice, Value: Choice::Tuple([0d], [0f 0e]) +Name: struct_variant, Id: _25, Ty: Choice, Value: Choice::Struct { n: [13 12 11 10], ok: [01] } Name: uninit_scalar, Id: _26, Ty: u32, Value: Name: , Id: _27, Ty: (u8, &u8, usize, &Aggregate, &(u8, u16), &TupleAggregate, &[u8; 3], &Nested, &Choice, &Choice, &Choice), Value: Name: , Id: _28, Ty: (u8, &u8, usize, &Aggregate, &(u8, u16), &TupleAggregate, &[u8; 3], &Nested, &Choice, &Choice, &Choice), Value: @@ -54,8 +54,8 @@ Name: , Id: _41, Ty: &[u8; 2], Value: {&_: &[u8; 2]} (priroda) Id: _18, Ty: TupleAggregate, Value: TupleAggregate([04], [06 05]) (priroda) Id: _19, Ty: [u8; 3], Value: [07 08 09] (priroda) Id: _20, Ty: Nested, Value: Nested { aggregate: Aggregate { byte: [0a], word: [0c 0b] }, tuple: [01 __ 03 02] } -(priroda) Id: _23, Ty: Choice, Value: [00 __ __ __ __ __ __ __] -(priroda) Id: _24, Ty: Choice, Value: [01 0d 0f 0e __ __ __ __] -(priroda) Id: _25, Ty: Choice, Value: [02 01 __ __ 13 12 11 10] +(priroda) Id: _23, Ty: Choice, Value: Choice::Unit +(priroda) Id: _24, Ty: Choice, Value: Choice::Tuple([0d], [0f 0e]) +(priroda) Id: _25, Ty: Choice, Value: Choice::Struct { n: [13 12 11 10], ok: [01] } (priroda) no local for this id (priroda) quitting From 65ee03d2190e1dc0305d54e561ea3bbe62a19c24 Mon Sep 17 00:00:00 2001 From: Mohamed Ali Date: Fri, 24 Jul 2026 13:16:37 +0300 Subject: [PATCH 09/23] [Priroda] Render source-shaped tuple values Render tuple operands as positional source-shaped values. Tuple elements are projected in source order and rendered through the existing leaf renderer, including the trailing comma for one-element tuples. --- src/tools/miri/priroda/src/main.rs | 23 +++++++++++++++++++ .../tests/ui/locals_corpus_async.stdout | 2 +- .../tests/ui/locals_source_shapes.stdout | 12 +++++----- .../tests/ui/locals_value_shapes.stdout | 8 +++---- 4 files changed, 34 insertions(+), 11 deletions(-) diff --git a/src/tools/miri/priroda/src/main.rs b/src/tools/miri/priroda/src/main.rs index 9799888a9804c..a8632c9273ff8 100644 --- a/src/tools/miri/priroda/src/main.rs +++ b/src/tools/miri/priroda/src/main.rs @@ -621,6 +621,29 @@ impl<'tcx> PrirodaContext<'tcx> { } } + ty::Tuple(args) => { + let mut fields = Vec::with_capacity(args.len()); + for i in 0..args.len() { + // Tuples have no field names in source, so preserve their + // source field order and render children positionally. + let field_op = + match self.ecx.project_field(&op, FieldIdx::from_usize(i)).discard_err() { + Some(field_op) => field_op, + // FIXME: render tuple fields independently so one + // projection failure does not throw away the whole + // source-shaped tuple. + None => return self.render_op(op), + }; + fields.push(self.render_source_shaped_op_inner(field_op, depth + 1)); + } + + if fields.len() == 1 { + format!("({},)", fields[0]) + } else { + format!("({})", fields.join(", ")) + } + } + // FIXME: consider source-shaped special cases for strings, closures, // generators/coroutines, trait objects, and SIMD/vector-like types. // Until then these stay on the raw renderer path. diff --git a/src/tools/miri/priroda/tests/ui/locals_corpus_async.stdout b/src/tools/miri/priroda/tests/ui/locals_corpus_async.stdout index 2d39662a81ab5..ddd3d5c13b2b4 100644 --- a/src/tools/miri/priroda/tests/ui/locals_corpus_async.stdout +++ b/src/tools/miri/priroda/tests/ui/locals_corpus_async.stdout @@ -7,7 +7,7 @@ (priroda) Hit breakpoint {MANIFEST_DIR}/tests/ui/locals_corpus_async.rs:31 (priroda) Name: , Id: _0, Ty: (), Value: -Name: , Id: _1, Ty: (u32, i32), Value: (0x00000005, 0x00000006): (u32, i32) +Name: , Id: _1, Ty: (u32, i32), Value: (5_u32, 6_i32) Name: first, Id: _1.0, Ty: u32, Value: 5_u32 Name: second, Id: _1.1, Ty: i32, Value: 6_i32 (priroda) Hit breakpoint diff --git a/src/tools/miri/priroda/tests/ui/locals_source_shapes.stdout b/src/tools/miri/priroda/tests/ui/locals_source_shapes.stdout index 5499312744ca3..b1707e0920a57 100644 --- a/src/tools/miri/priroda/tests/ui/locals_source_shapes.stdout +++ b/src/tools/miri/priroda/tests/ui/locals_source_shapes.stdout @@ -8,9 +8,9 @@ Name: unit_struct, Id: _3, Ty: UnitStruct, Value: UnitStruct Name: tuple_struct, Id: _4, Ty: TupleStruct, Value: TupleStruct([04], [05 06]) Name: single_tuple_struct, Id: _5, Ty: SingleTupleStruct, Value: SingleTupleStruct([07]) Name: zero_tuple_struct, Id: _6, Ty: ZeroTupleStruct, Value: ZeroTupleStruct() -Name: tuple_zero, Id: _7, Ty: (), Value: [] -Name: tuple_one, Id: _8, Ty: (u8,), Value: [08] -Name: tuple_many, Id: _9, Ty: (u8, u16), Value: [09 __ 0a 0b] +Name: tuple_zero, Id: _7, Ty: (), Value: () +Name: tuple_one, Id: _8, Ty: (u8,), Value: ([08],) +Name: tuple_many, Id: _9, Ty: (u8, u16), Value: ([09], [0a 0b]) Name: array_zero, Id: _10, Ty: [u8; 0], Value: [] Name: array_one, Id: _11, Ty: [u8; 1], Value: [0c] Name: array_many, Id: _12, Ty: [u8; 3], Value: [0d 0e 0f] @@ -47,9 +47,9 @@ Name: , Id: _39, Ty: u8, Value: (priroda) Id: _4, Ty: TupleStruct, Value: TupleStruct([04], [05 06]) (priroda) Id: _5, Ty: SingleTupleStruct, Value: SingleTupleStruct([07]) (priroda) Id: _6, Ty: ZeroTupleStruct, Value: ZeroTupleStruct() -(priroda) Id: _7, Ty: (), Value: [] -(priroda) Id: _8, Ty: (u8,), Value: [08] -(priroda) Id: _9, Ty: (u8, u16), Value: [09 __ 0a 0b] +(priroda) Id: _7, Ty: (), Value: () +(priroda) Id: _8, Ty: (u8,), Value: ([08],) +(priroda) Id: _9, Ty: (u8, u16), Value: ([09], [0a 0b]) (priroda) Id: _10, Ty: [u8; 0], Value: [] (priroda) Id: _11, Ty: [u8; 1], Value: [0c] (priroda) Id: _12, Ty: [u8; 3], Value: [0d 0e 0f] diff --git a/src/tools/miri/priroda/tests/ui/locals_value_shapes.stdout b/src/tools/miri/priroda/tests/ui/locals_value_shapes.stdout index 20b8d670dc124..a3c0c3650d78f 100644 --- a/src/tools/miri/priroda/tests/ui/locals_value_shapes.stdout +++ b/src/tools/miri/priroda/tests/ui/locals_value_shapes.stdout @@ -18,10 +18,10 @@ Name: , Id: _13, Ty: [u8; 2], Value: Name: , Id: _14, Ty: std::ops::RangeFull, Value: Name: mplace, Id: _15, Ty: Aggregate, Value: Aggregate { byte: [2a], word: [34 12] } Name: , Id: _16, Ty: u8, Value: -Name: tuple, Id: _17, Ty: (u8, u16), Value: [01 __ 03 02] +Name: tuple, Id: _17, Ty: (u8, u16), Value: ([01], [03 02]) Name: tuple_struct, Id: _18, Ty: TupleAggregate, Value: TupleAggregate([04], [06 05]) Name: array, Id: _19, Ty: [u8; 3], Value: [07 08 09] -Name: nested, Id: _20, Ty: Nested, Value: Nested { aggregate: Aggregate { byte: [0a], word: [0c 0b] }, tuple: [01 __ 03 02] } +Name: nested, Id: _20, Ty: Nested, Value: Nested { aggregate: Aggregate { byte: [0a], word: [0c 0b] }, tuple: ([01], [03 02]) } Name: , Id: _21, Ty: Aggregate, Value: Name: , Id: _22, Ty: (u8, u16), Value: Name: unit_variant, Id: _23, Ty: Choice, Value: Choice::Unit @@ -50,10 +50,10 @@ Name: , Id: _41, Ty: &[u8; 2], Value: {&_: &[u8; 2]} (priroda) Id: _8, Ty: u8, Value: [33] (priroda) Id: _13, Ty: [u8; 2], Value: (priroda) Id: _15, Ty: Aggregate, Value: Aggregate { byte: [2a], word: [34 12] } -(priroda) Id: _17, Ty: (u8, u16), Value: [01 __ 03 02] +(priroda) Id: _17, Ty: (u8, u16), Value: ([01], [03 02]) (priroda) Id: _18, Ty: TupleAggregate, Value: TupleAggregate([04], [06 05]) (priroda) Id: _19, Ty: [u8; 3], Value: [07 08 09] -(priroda) Id: _20, Ty: Nested, Value: Nested { aggregate: Aggregate { byte: [0a], word: [0c 0b] }, tuple: [01 __ 03 02] } +(priroda) Id: _20, Ty: Nested, Value: Nested { aggregate: Aggregate { byte: [0a], word: [0c 0b] }, tuple: ([01], [03 02]) } (priroda) Id: _23, Ty: Choice, Value: Choice::Unit (priroda) Id: _24, Ty: Choice, Value: Choice::Tuple([0d], [0f 0e]) (priroda) Id: _25, Ty: Choice, Value: Choice::Struct { n: [13 12 11 10], ok: [01] } From 77b975cd0e7ea6875d9af7b4ffbcf1d5ccf42a94 Mon Sep 17 00:00:00 2001 From: Mohamed Ali Date: Fri, 24 Jul 2026 13:17:01 +0300 Subject: [PATCH 10/23] [Priroda] Render source-shaped array and slice values Render array and slice operands as ordered source-shaped elements. Fixed arrays use their layout count while slices use the runtime metadata length, then `project_array_fields` supplies the element operands for raw-leaf rendering. --- src/tools/miri/priroda/src/main.rs | 28 +++++++++++++++++++ .../tests/ui/locals_mplace_metadata.stdout | 4 +-- .../tests/ui/locals_pointer_rendering.stdout | 6 ++-- .../tests/ui/locals_source_shapes.stdout | 8 +++--- .../tests/ui/locals_source_slices.stdout | 8 +++--- .../tests/ui/locals_value_shapes.stdout | 4 +-- 6 files changed, 43 insertions(+), 15 deletions(-) diff --git a/src/tools/miri/priroda/src/main.rs b/src/tools/miri/priroda/src/main.rs index a8632c9273ff8..bc0dacc589a79 100644 --- a/src/tools/miri/priroda/src/main.rs +++ b/src/tools/miri/priroda/src/main.rs @@ -644,6 +644,34 @@ impl<'tcx> PrirodaContext<'tcx> { } } + ty::Array(_, _) | ty::Slice(_) => { + // `project_array_fields` uses the dynamic length for slices. That + // avoids the classic mistake of treating slice layout as a fixed + // zero-length array. + let mut iter = match self.ecx.project_array_fields(&op).discard_err() { + Some(iter) => iter, + // FIXME: when slice metadata is invalid, show that as a slice + // length problem instead of silently falling back to raw bytes. + None => return self.render_op(op), + }; + + let mut fields = Vec::new(); + // FIXME: add an output budget/truncation policy before rendering + // very large arrays or slices in full. + loop { + match iter.next(&self.ecx).discard_err() { + Some(Some((_idx, field_op))) => + fields.push(self.render_source_shaped_op_inner(field_op, depth + 1)), + Some(None) => break, + // FIXME: keep already-rendered elements and mark the + // failed index once partial render errors are supported. + None => return self.render_op(op), + } + } + + format!("[{}]", fields.join(", ")) + } + // FIXME: consider source-shaped special cases for strings, closures, // generators/coroutines, trait objects, and SIMD/vector-like types. // Until then these stay on the raw renderer path. diff --git a/src/tools/miri/priroda/tests/ui/locals_mplace_metadata.stdout b/src/tools/miri/priroda/tests/ui/locals_mplace_metadata.stdout index 3a92ca95a5b68..c8088805d3482 100644 --- a/src/tools/miri/priroda/tests/ui/locals_mplace_metadata.stdout +++ b/src/tools/miri/priroda/tests/ui/locals_mplace_metadata.stdout @@ -4,10 +4,10 @@ (priroda) Hit breakpoint {MANIFEST_DIR}/tests/ui/locals_mplace_metadata.rs:8 (priroda) Name: , Id: _0, Ty: (), Value: -Name: slice, Id: _1, Ty: [u8], Value: [01 02 03] +Name: slice, Id: _1, Ty: [u8], Value: [[01], [02], [03]] Name: , Id: _2, Ty: &[u8], Value: Name: , Id: _3, Ty: &[u8], Value: -(priroda) Id: _1, Ty: [u8], Value: [01 02 03] +(priroda) Id: _1, Ty: [u8], Value: [[01], [02], [03]] (priroda) Hit breakpoint {MANIFEST_DIR}/tests/ui/locals_mplace_metadata.rs:12 (priroda) Name: , Id: _0, Ty: (), Value: diff --git a/src/tools/miri/priroda/tests/ui/locals_pointer_rendering.stdout b/src/tools/miri/priroda/tests/ui/locals_pointer_rendering.stdout index 27d37e4940acb..b3d61198e813c 100644 --- a/src/tools/miri/priroda/tests/ui/locals_pointer_rendering.stdout +++ b/src/tools/miri/priroda/tests/ui/locals_pointer_rendering.stdout @@ -2,13 +2,13 @@ (priroda) Hit breakpoint {MANIFEST_DIR}/tests/ui/locals_pointer_rendering.rs:59 (priroda) Name: , Id: _0, Ty: (), Value: -Name: target, Id: _1, Ty: [u8; 2], Value: [0a 14] +Name: target, Id: _1, Ty: [u8; 2], Value: [[0a], [14]] Name: pointer_at_offset0, Id: _2, Ty: PointerAtOffset0<'_>, Value: PointerAtOffset0 { ptr: [{ALLOC_PTR}] } Name: , Id: _3, Ty: &u8, Value: Name: , Id: _4, Ty: &u8, Value: Name: , Id: _5, Ty: usize, Value: Name: , Id: _6, Ty: bool, Value: true -Name: pointer_after_bytes, Id: _7, Ty: PointerAfterBytes<'_>, Value: PointerAfterBytes { bytes: [01 02 03], ptr: [{ALLOC_PTR}] } +Name: pointer_after_bytes, Id: _7, Ty: PointerAfterBytes<'_>, Value: PointerAfterBytes { bytes: [[01], [02], [03]], ptr: [{ALLOC_PTR}] } Name: , Id: _8, Ty: [u8; 3], Value: Name: , Id: _9, Ty: &u8, Value: Name: , Id: _10, Ty: &u8, Value: @@ -32,7 +32,7 @@ Name: , Id: _27, Ty: &u8, Value: Name: , Id: _28, Ty: usize, Value: Name: , Id: _29, Ty: bool, Value: true Name: fixed_addr_ptr, Id: _30, Ty: *const u8, Value: [0x1234[wildcard]] -Name: short_pointer_bytes, Id: _31, Ty: [u8; 1], Value: [34] +Name: short_pointer_bytes, Id: _31, Ty: [u8; 1], Value: [[34]] Name: bytes, Id: _32, Ty: std::mem::MaybeUninit<[u8; 1]>, Value: Name: , Id: _33, Ty: (), Value: Name: , Id: _34, Ty: *const u8, Value: diff --git a/src/tools/miri/priroda/tests/ui/locals_source_shapes.stdout b/src/tools/miri/priroda/tests/ui/locals_source_shapes.stdout index b1707e0920a57..b115fd17b4875 100644 --- a/src/tools/miri/priroda/tests/ui/locals_source_shapes.stdout +++ b/src/tools/miri/priroda/tests/ui/locals_source_shapes.stdout @@ -12,8 +12,8 @@ Name: tuple_zero, Id: _7, Ty: (), Value: () Name: tuple_one, Id: _8, Ty: (u8,), Value: ([08],) Name: tuple_many, Id: _9, Ty: (u8, u16), Value: ([09], [0a 0b]) Name: array_zero, Id: _10, Ty: [u8; 0], Value: [] -Name: array_one, Id: _11, Ty: [u8; 1], Value: [0c] -Name: array_many, Id: _12, Ty: [u8; 3], Value: [0d 0e 0f] +Name: array_one, Id: _11, Ty: [u8; 1], Value: [[0c]] +Name: array_many, Id: _12, Ty: [u8; 3], Value: [[0d], [0e], [0f]] Name: variant_unit, Id: _13, Ty: Variants, Value: Variants::Unit Name: variant_tuple, Id: _14, Ty: Variants, Value: Variants::Tuple([10], [11 12]) Name: variant_single_tuple, Id: _15, Ty: Variants, Value: Variants::SingleTuple([13]) @@ -51,8 +51,8 @@ Name: , Id: _39, Ty: u8, Value: (priroda) Id: _8, Ty: (u8,), Value: ([08],) (priroda) Id: _9, Ty: (u8, u16), Value: ([09], [0a 0b]) (priroda) Id: _10, Ty: [u8; 0], Value: [] -(priroda) Id: _11, Ty: [u8; 1], Value: [0c] -(priroda) Id: _12, Ty: [u8; 3], Value: [0d 0e 0f] +(priroda) Id: _11, Ty: [u8; 1], Value: [[0c]] +(priroda) Id: _12, Ty: [u8; 3], Value: [[0d], [0e], [0f]] (priroda) Id: _13, Ty: Variants, Value: Variants::Unit (priroda) Id: _14, Ty: Variants, Value: Variants::Tuple([10], [11 12]) (priroda) Id: _15, Ty: Variants, Value: Variants::SingleTuple([13]) diff --git a/src/tools/miri/priroda/tests/ui/locals_source_slices.stdout b/src/tools/miri/priroda/tests/ui/locals_source_slices.stdout index b7444efa9150e..15467092102fa 100644 --- a/src/tools/miri/priroda/tests/ui/locals_source_slices.stdout +++ b/src/tools/miri/priroda/tests/ui/locals_source_slices.stdout @@ -11,15 +11,15 @@ Name: , Id: _3, Ty: &[u8], Value: (priroda) Hit breakpoint {MANIFEST_DIR}/tests/ui/locals_source_slices.rs:8 (priroda) Name: , Id: _0, Ty: (), Value: -Name: slice, Id: _1, Ty: [u8], Value: [1a] +Name: slice, Id: _1, Ty: [u8], Value: [[1a]] Name: , Id: _2, Ty: &[u8], Value: Name: , Id: _3, Ty: &[u8], Value: -(priroda) Id: _1, Ty: [u8], Value: [1a] +(priroda) Id: _1, Ty: [u8], Value: [[1a]] (priroda) Hit breakpoint {MANIFEST_DIR}/tests/ui/locals_source_slices.rs:12 (priroda) Name: , Id: _0, Ty: (), Value: -Name: slice, Id: _1, Ty: [u8], Value: [1b 1c] +Name: slice, Id: _1, Ty: [u8], Value: [[1b], [1c]] Name: , Id: _2, Ty: &[u8], Value: Name: , Id: _3, Ty: &[u8], Value: -(priroda) Id: _1, Ty: [u8], Value: [1b 1c] +(priroda) Id: _1, Ty: [u8], Value: [[1b], [1c]] (priroda) quitting diff --git a/src/tools/miri/priroda/tests/ui/locals_value_shapes.stdout b/src/tools/miri/priroda/tests/ui/locals_value_shapes.stdout index a3c0c3650d78f..46f688a2d490e 100644 --- a/src/tools/miri/priroda/tests/ui/locals_value_shapes.stdout +++ b/src/tools/miri/priroda/tests/ui/locals_value_shapes.stdout @@ -20,7 +20,7 @@ Name: mplace, Id: _15, Ty: Aggregate, Value: Aggregate { byte: [2a], word: [34 1 Name: , Id: _16, Ty: u8, Value: Name: tuple, Id: _17, Ty: (u8, u16), Value: ([01], [03 02]) Name: tuple_struct, Id: _18, Ty: TupleAggregate, Value: TupleAggregate([04], [06 05]) -Name: array, Id: _19, Ty: [u8; 3], Value: [07 08 09] +Name: array, Id: _19, Ty: [u8; 3], Value: [[07], [08], [09]] Name: nested, Id: _20, Ty: Nested, Value: Nested { aggregate: Aggregate { byte: [0a], word: [0c 0b] }, tuple: ([01], [03 02]) } Name: , Id: _21, Ty: Aggregate, Value: Name: , Id: _22, Ty: (u8, u16), Value: @@ -52,7 +52,7 @@ Name: , Id: _41, Ty: &[u8; 2], Value: {&_: &[u8; 2]} (priroda) Id: _15, Ty: Aggregate, Value: Aggregate { byte: [2a], word: [34 12] } (priroda) Id: _17, Ty: (u8, u16), Value: ([01], [03 02]) (priroda) Id: _18, Ty: TupleAggregate, Value: TupleAggregate([04], [06 05]) -(priroda) Id: _19, Ty: [u8; 3], Value: [07 08 09] +(priroda) Id: _19, Ty: [u8; 3], Value: [[07], [08], [09]] (priroda) Id: _20, Ty: Nested, Value: Nested { aggregate: Aggregate { byte: [0a], word: [0c 0b] }, tuple: ([01], [03 02]) } (priroda) Id: _23, Ty: Choice, Value: Choice::Unit (priroda) Id: _24, Ty: Choice, Value: Choice::Tuple([0d], [0f 0e]) From 925bc0ef7a6dbd096e55e5da7a5f239a668ca005 Mon Sep 17 00:00:00 2001 From: zjp Date: Tue, 28 Jul 2026 11:58:35 +0800 Subject: [PATCH 11/23] fix ptr_from_addr_cast comment --- src/tools/miri/src/alloc_addresses/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index 8b8fff412b7a4..72337a3e6bced 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -379,7 +379,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ProvenanceMode::Permissive => {} } - // We do *not* look up the `AllocId` here! This is a `ptr as usize` cast, and it is + // We do *not* look up the `AllocId` here! This is a `usize as ptr` cast, and it is // completely legal to do a cast and then `wrapping_offset` to another allocation and only // *then* do a memory access. So the allocation that the pointer happens to point to on a // cast is fairly irrelevant. Instead we generate this as a "wildcard" pointer, such that From d2037828b32041c7e5cd73795d1899aaf6c4ba28 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Tue, 28 Jul 2026 05:25:12 +0000 Subject: [PATCH 12/23] Prepare for merging from rust-lang/rust This updates the rust-version file to d3ea0356830dc019038110eba0bc8f790aaef2e4. --- 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 57e0ac6d84e12..5a25584457ac8 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -dfbea5bc945a9d7ff017d3d4bfbd1af9295fe5b8 +d3ea0356830dc019038110eba0bc8f790aaef2e4 From 204ccaa4efa49ed048566ff65fb878b6c5b029e8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 28 Jul 2026 08:35:23 +0200 Subject: [PATCH 13/23] tests: libc-poll: test a more reaosnable FD number for POLLNVAL --- src/tools/miri/tests/pass-dep/libc/libc-poll.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/tests/pass-dep/libc/libc-poll.rs b/src/tools/miri/tests/pass-dep/libc/libc-poll.rs index cec68d7ae88fb..2d938b22504ea 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-poll.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-poll.rs @@ -130,7 +130,7 @@ fn test_poll_negative_fd_interest() { /// when an invalid non-negative file descriptor is provided, and that /// `poll` instantly returns. fn test_poll_invalid_non_negative_fd_interest() { - let mut interests = [libc::pollfd { fd: libc::c_int::MAX, events: libc::POLLHUP, revents: 0 }]; + let mut interests = [libc::pollfd { fd: 1337, events: libc::POLLHUP, revents: 0 }]; // We provide an "infinite" timeout because interests in invalid non-negative file descriptors // are considered fulfilled and the `poll` invocation should thus instantly return. From 9c4c3fe583478f3acd3bb654255421cbce3d4177 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 28 Jul 2026 08:39:45 +0200 Subject: [PATCH 14/23] macos poll seems be kinda broken --- src/tools/miri/tests/pass-dep/libc/libc-poll-std-handles.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/tools/miri/tests/pass-dep/libc/libc-poll-std-handles.rs b/src/tools/miri/tests/pass-dep/libc/libc-poll-std-handles.rs index bcff187859546..e56401ca67330 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-poll-std-handles.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-poll-std-handles.rs @@ -17,6 +17,12 @@ fn main() { let num = errno_result(unsafe { libc::poll(pfds.as_mut_ptr(), 3, 0) }).unwrap(); assert_eq!(num, 3); + if cfg!(target_vendor = "apple") && !cfg!(miri) { + // The native macOS poll behaves very strangely. It apparently reports POLLNVAL for stdin? + // std does not even use poll for `sanitize_standard_fds` because of that. + return; + } + assert_eq!(pfds[0].revents, libc::POLLIN | libc::POLLOUT); assert_eq!(pfds[1].revents, libc::POLLOUT); assert_eq!(pfds[2].revents, libc::POLLOUT); From c10cc834319227c6301d4b77f2772e02fe3cca9c Mon Sep 17 00:00:00 2001 From: jrakibi Date: Sat, 11 Jul 2026 18:59:20 +0800 Subject: [PATCH 15/23] add aarch64 SHA256 intrinsics Implement shims for vsha256hq_u32, vsha256h2q_u32, vsha256su0q_u32 and vsha256su1q_u32 --- src/tools/miri/src/intrinsics/aarch64.rs | 157 ++++++++++- src/tools/miri/src/intrinsics/math.rs | 36 +++ src/tools/miri/src/intrinsics/x86/sha.rs | 104 ++----- .../shims/aarch64/intrinsics-aarch64-sha.rs | 266 ++++++++++++++++++ 4 files changed, 476 insertions(+), 87 deletions(-) create mode 100644 src/tools/miri/tests/pass/shims/aarch64/intrinsics-aarch64-sha.rs diff --git a/src/tools/miri/src/intrinsics/aarch64.rs b/src/tools/miri/src/intrinsics/aarch64.rs index 626a83a65a238..df513feca0780 100644 --- a/src/tools/miri/src/intrinsics/aarch64.rs +++ b/src/tools/miri/src/intrinsics/aarch64.rs @@ -1,7 +1,7 @@ use rustc_middle::mir::BinOp; use rustc_span::Symbol; -use crate::intrinsics::math::compute_crc32; +use crate::intrinsics::math::{compute_crc32, sha256}; use crate::*; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} @@ -314,8 +314,163 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(Scalar::from_u128(result), &dest)?; } + // Used to implement the vsha256hq_u32 function. + // https://developer.arm.com/architectures/instruction-sets/intrinsics/vsha256hq_u32 + "crypto.sha256h" => { + this.expect_target_feature_for_intrinsic(link_name, "sha2")?; + + let [abcd, efgh, wk] = this.check_shim_sig_unadjusted(link_name, args)?; + + let (abcd, abcd_len) = this.project_to_simd(abcd)?; + let (efgh, efgh_len) = this.project_to_simd(efgh)?; + let (wk, wk_len) = this.project_to_simd(wk)?; + let (dest, dest_len) = this.project_to_simd(dest)?; + + assert_eq!(abcd_len, 4); + assert_eq!(efgh_len, 4); + assert_eq!(wk_len, 4); + assert_eq!(dest_len, 4); + + let abcd: [u32; 4] = read_u32x4(this, &abcd)?; + let efgh: [u32; 4] = read_u32x4(this, &efgh)?; + let wk: [u32; 4] = read_u32x4(this, &wk)?; + + let result = sha256h(abcd, efgh, wk); + + write_u32x4(this, &dest, result)?; + } + // Used to implement the vsha256h2q_u32 function. + // https://developer.arm.com/architectures/instruction-sets/intrinsics/vsha256h2q_u32 + "crypto.sha256h2" => { + this.expect_target_feature_for_intrinsic(link_name, "sha2")?; + + let [efgh, abcd, wk] = this.check_shim_sig_unadjusted(link_name, args)?; + + let (efgh, efgh_len) = this.project_to_simd(efgh)?; + let (abcd, abcd_len) = this.project_to_simd(abcd)?; + let (wk, wk_len) = this.project_to_simd(wk)?; + let (dest, dest_len) = this.project_to_simd(dest)?; + + assert_eq!(efgh_len, 4); + assert_eq!(abcd_len, 4); + assert_eq!(wk_len, 4); + assert_eq!(dest_len, 4); + + let efgh: [u32; 4] = read_u32x4(this, &efgh)?; + let abcd: [u32; 4] = read_u32x4(this, &abcd)?; + let wk: [u32; 4] = read_u32x4(this, &wk)?; + + let result = sha256h2(efgh, abcd, wk); + + write_u32x4(this, &dest, result)?; + } + // Used to implement the vsha256su0q_u32 function. + // https://developer.arm.com/architectures/instruction-sets/intrinsics/vsha256su0q_u32 + "crypto.sha256su0" => { + this.expect_target_feature_for_intrinsic(link_name, "sha2")?; + + let [a, b] = this.check_shim_sig_unadjusted(link_name, args)?; + + let (a, a_len) = this.project_to_simd(a)?; + let (b, b_len) = this.project_to_simd(b)?; + let (dest, dest_len) = this.project_to_simd(dest)?; + + assert_eq!(a_len, 4); + assert_eq!(b_len, 4); + assert_eq!(dest_len, 4); + + let a: [u32; 4] = read_u32x4(this, &a)?; + let b: [u32; 4] = read_u32x4(this, &b)?; + + let result = sha256su0(a, b); + + write_u32x4(this, &dest, result)?; + } + // Used to implement the vsha256su1q_u32 function. + // https://developer.arm.com/architectures/instruction-sets/intrinsics/vsha256su1q_u32 + "crypto.sha256su1" => { + this.expect_target_feature_for_intrinsic(link_name, "sha2")?; + + let [a, b, c] = this.check_shim_sig_unadjusted(link_name, args)?; + + let (a, a_len) = this.project_to_simd(a)?; + let (b, b_len) = this.project_to_simd(b)?; + let (c, c_len) = this.project_to_simd(c)?; + let (dest, dest_len) = this.project_to_simd(dest)?; + + assert_eq!(a_len, 4); + assert_eq!(b_len, 4); + assert_eq!(c_len, 4); + assert_eq!(dest_len, 4); + + let a: [u32; 4] = read_u32x4(this, &a)?; + let b: [u32; 4] = read_u32x4(this, &b)?; + let c: [u32; 4] = read_u32x4(this, &c)?; + + let result = sha256su1(a, b, c); + + write_u32x4(this, &dest, result)?; + } _ => return interp_ok(EmulateItemResult::NotSupported), } interp_ok(EmulateItemResult::NeedsReturn) } } + +/// Reads a `[u32; 4]` array. +fn read_u32x4<'c>(ecx: &mut MiriInterpCx<'c>, vec: &OpTy<'c>) -> InterpResult<'c, [u32; 4]> { + let mut res = [0; 4]; + for (i, dst) in res.iter_mut().enumerate() { + let projected = &ecx.project_index(vec, i.try_into().unwrap())?; + *dst = ecx.read_scalar(projected)?.to_u32()?; + } + interp_ok(res) +} + +fn write_u32x4<'c>( + ecx: &mut MiriInterpCx<'c>, + dest: &MPlaceTy<'c>, + val: [u32; 4], +) -> InterpResult<'c, ()> { + for (i, part) in val.into_iter().enumerate() { + let projected = &ecx.project_index(dest, i.to_u64())?; + ecx.write_scalar(Scalar::from_u32(part), projected)?; + } + interp_ok(()) +} + +fn sha256su0(v0: [u32; 4], v1: [u32; 4]) -> [u32; 4] { + [ + v0[0].wrapping_add(sha256::sigma0(v0[1])), + v0[1].wrapping_add(sha256::sigma0(v0[2])), + v0[2].wrapping_add(sha256::sigma0(v0[3])), + v0[3].wrapping_add(sha256::sigma0(v1[0])), + ] +} + +fn sha256su1(v0: [u32; 4], v1: [u32; 4], v2: [u32; 4]) -> [u32; 4] { + let r0 = v0[0].wrapping_add(v1[1]).wrapping_add(sha256::sigma1(v2[2])); + let r1 = v0[1].wrapping_add(v1[2]).wrapping_add(sha256::sigma1(v2[3])); + let r2 = v0[2].wrapping_add(v1[3]).wrapping_add(sha256::sigma1(r0)); + let r3 = v0[3].wrapping_add(v2[0]).wrapping_add(sha256::sigma1(r1)); + [r0, r1, r2, r3] +} + +// SHA256H/SHA256H2 do four compression rounds on the abcd/efgh layout. +// https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiesinstructiongroup=[Cryptography,SHA256] +fn sha256hash(abcd: [u32; 4], efgh: [u32; 4], wk: [u32; 4]) -> ([u32; 4], [u32; 4]) { + let mut state = [abcd[0], abcd[1], abcd[2], abcd[3], efgh[0], efgh[1], efgh[2], efgh[3]]; + for &wk_i in &wk { + state = sha256::round(state, wk_i); + } + ([state[0], state[1], state[2], state[3]], [state[4], state[5], state[6], state[7]]) +} + +fn sha256h(abcd: [u32; 4], efgh: [u32; 4], wk: [u32; 4]) -> [u32; 4] { + sha256hash(abcd, efgh, wk).0 +} + +// sha256h2 takes efgh as the first argument. abcd and efgh are swapped when calling sha256hash. +fn sha256h2(efgh: [u32; 4], abcd: [u32; 4], wk: [u32; 4]) -> [u32; 4] { + sha256hash(abcd, efgh, wk).1 +} diff --git a/src/tools/miri/src/intrinsics/math.rs b/src/tools/miri/src/intrinsics/math.rs index d6bb9a7b52e72..adb768e6bcffc 100644 --- a/src/tools/miri/src/intrinsics/math.rs +++ b/src/tools/miri/src/intrinsics/math.rs @@ -253,3 +253,39 @@ pub(crate) fn compute_crc32(crc: u32, data: u64, bit_size: u32, polynomial: u128 u32::try_from(dividend).unwrap().reverse_bits() } + +// sha256 primitives shared by the x86 and aarch64 intrinsics. Math helpers adapted from RustCrypto soft impl: +// https://github.com/RustCrypto/hashes/blob/3d2bc57db40fd6aeb25d6c6da98d67e2784c2985/sha2/src/sha256/soft/compact.rs +pub(crate) mod sha256 { + pub(crate) fn sigma0(x: u32) -> u32 { + x.rotate_right(7) ^ x.rotate_right(18) ^ (x >> 3) + } + + pub(crate) fn sigma1(x: u32) -> u32 { + x.rotate_right(17) ^ x.rotate_right(19) ^ (x >> 10) + } + + /// One round of the compression; `wk` is the round's `w[i] + k[i]`. + pub(crate) fn round(state: [u32; 8], wk: u32) -> [u32; 8] { + let [a, b, c, d, e, f, g, h] = state; + + let s1 = e.rotate_right(6) ^ e.rotate_right(11) ^ e.rotate_right(25); + let ch = (e & f) ^ ((!e) & g); + let t1 = s1.wrapping_add(ch).wrapping_add(wk).wrapping_add(h); + + let s0 = a.rotate_right(2) ^ a.rotate_right(13) ^ a.rotate_right(22); + let maj = (a & b) ^ (a & c) ^ (b & c); + let t2 = s0.wrapping_add(maj); + + [ + t1.wrapping_add(t2), // a + a, // b + b, // c + c, // d + d.wrapping_add(t1), // e + e, // f + f, // g + g, // h + ] + } +} diff --git a/src/tools/miri/src/intrinsics/x86/sha.rs b/src/tools/miri/src/intrinsics/x86/sha.rs index 982e3a08e4826..d7f17c8d6e383 100644 --- a/src/tools/miri/src/intrinsics/x86/sha.rs +++ b/src/tools/miri/src/intrinsics/x86/sha.rs @@ -6,6 +6,7 @@ use rustc_span::Symbol; +use crate::intrinsics::math::sha256; use crate::*; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} @@ -110,110 +111,41 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } -#[inline(always)] -fn shr(v: [u32; 4], o: u32) -> [u32; 4] { - [v[0] >> o, v[1] >> o, v[2] >> o, v[3] >> o] -} - -#[inline(always)] -fn shl(v: [u32; 4], o: u32) -> [u32; 4] { - [v[0] << o, v[1] << o, v[2] << o, v[3] << o] -} - -#[inline(always)] -fn or(a: [u32; 4], b: [u32; 4]) -> [u32; 4] { - [a[0] | b[0], a[1] | b[1], a[2] | b[2], a[3] | b[3]] -} - -#[inline(always)] -fn xor(a: [u32; 4], b: [u32; 4]) -> [u32; 4] { - [a[0] ^ b[0], a[1] ^ b[1], a[2] ^ b[2], a[3] ^ b[3]] -} - -#[inline(always)] -fn add(a: [u32; 4], b: [u32; 4]) -> [u32; 4] { - [ - a[0].wrapping_add(b[0]), - a[1].wrapping_add(b[1]), - a[2].wrapping_add(b[2]), - a[3].wrapping_add(b[3]), - ] -} - fn sha256load(v2: [u32; 4], v3: [u32; 4]) -> [u32; 4] { [v3[3], v2[0], v2[1], v2[2]] } fn sha256_digest_round_x2(cdgh: [u32; 4], abef: [u32; 4], wk: [u32; 4]) -> [u32; 4] { - macro_rules! big_sigma0 { - ($a:expr) => { - ($a.rotate_right(2) ^ $a.rotate_right(13) ^ $a.rotate_right(22)) - }; - } - macro_rules! big_sigma1 { - ($a:expr) => { - ($a.rotate_right(6) ^ $a.rotate_right(11) ^ $a.rotate_right(25)) - }; - } - macro_rules! bool3ary_202 { - ($a:expr, $b:expr, $c:expr) => { - $c ^ ($a & ($b ^ $c)) - }; - } // Choose, MD5F, SHA1C - macro_rules! bool3ary_232 { - ($a:expr, $b:expr, $c:expr) => { - ($a & $b) ^ ($a & $c) ^ ($b & $c) - }; - } // Majority, SHA1M - + // `sha256rnds2`: two rounds on the abef/cdgh permutation + // Ref: https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sha256rnds2 let [_, _, wk1, wk0] = wk; let [a0, b0, e0, f0] = abef; let [c0, d0, g0, h0] = cdgh; - // a round - let x0 = - big_sigma1!(e0).wrapping_add(bool3ary_202!(e0, f0, g0)).wrapping_add(wk0).wrapping_add(h0); - let y0 = big_sigma0!(a0).wrapping_add(bool3ary_232!(a0, b0, c0)); - let (a1, b1, c1, d1, e1, f1, g1, h1) = - (x0.wrapping_add(y0), a0, b0, c0, x0.wrapping_add(d0), e0, f0, g0); - - // a round - let x1 = - big_sigma1!(e1).wrapping_add(bool3ary_202!(e1, f1, g1)).wrapping_add(wk1).wrapping_add(h1); - let y1 = big_sigma0!(a1).wrapping_add(bool3ary_232!(a1, b1, c1)); - let (a2, b2, _, _, e2, f2, _, _) = - (x1.wrapping_add(y1), a1, b1, c1, x1.wrapping_add(d1), e1, f1, g1); - - [a2, b2, e2, f2] + let state = sha256::round([a0, b0, c0, d0, e0, f0, g0, h0], wk0); + let state = sha256::round(state, wk1); + + [state[0], state[1], state[4], state[5]] } fn sha256msg1(v0: [u32; 4], v1: [u32; 4]) -> [u32; 4] { - // sigma 0 on vectors - #[inline] - fn sigma0x4(x: [u32; 4]) -> [u32; 4] { - let t1 = or(shr(x, 7), shl(x, 25)); - let t2 = or(shr(x, 18), shl(x, 14)); - let t3 = shr(x, 3); - xor(xor(t1, t2), t3) - } - - add(v0, sigma0x4(sha256load(v0, v1))) + let x = sha256load(v0, v1); + [ + v0[0].wrapping_add(sha256::sigma0(x[0])), + v0[1].wrapping_add(sha256::sigma0(x[1])), + v0[2].wrapping_add(sha256::sigma0(x[2])), + v0[3].wrapping_add(sha256::sigma0(x[3])), + ] } fn sha256msg2(v4: [u32; 4], v3: [u32; 4]) -> [u32; 4] { - macro_rules! sigma1 { - ($a:expr) => { - $a.rotate_right(17) ^ $a.rotate_right(19) ^ ($a >> 10) - }; - } - let [x3, x2, x1, x0] = v4; let [w15, w14, _, _] = v3; - let w16 = x0.wrapping_add(sigma1!(w14)); - let w17 = x1.wrapping_add(sigma1!(w15)); - let w18 = x2.wrapping_add(sigma1!(w16)); - let w19 = x3.wrapping_add(sigma1!(w17)); + let w16 = x0.wrapping_add(sha256::sigma1(w14)); + let w17 = x1.wrapping_add(sha256::sigma1(w15)); + let w18 = x2.wrapping_add(sha256::sigma1(w16)); + let w19 = x3.wrapping_add(sha256::sigma1(w17)); [w19, w18, w17, w16] } diff --git a/src/tools/miri/tests/pass/shims/aarch64/intrinsics-aarch64-sha.rs b/src/tools/miri/tests/pass/shims/aarch64/intrinsics-aarch64-sha.rs new file mode 100644 index 0000000000000..78e2ef53037b9 --- /dev/null +++ b/src/tools/miri/tests/pass/shims/aarch64/intrinsics-aarch64-sha.rs @@ -0,0 +1,266 @@ +//@only-target: aarch64 +//@compile-flags: -C target-feature=+sha2 +//@run-native + +use std::arch::aarch64::*; +use std::fmt::Write; + +fn main() { + assert!(std::arch::is_aarch64_feature_detected!("sha2")); + unsafe { + test_sha256(); + test_sha256_vectors(); + } +} + +/// Tests the SHA256 intrinsics end-to-end +#[target_feature(enable = "sha2")] +unsafe fn test_sha256() { + const INITIAL_STATE: [u32; 8] = [ + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, + 0x5be0cd19, + ]; + + // same message as the x86 SHA test. + let first_block = *b"Rust is awesome!Rust is awesome!Rust is awesome!Rust is awesome!"; + + // SHA256 padding: 0x80 byte, zeros, then message length in bits as big endian u64. + let mut final_block = [0u8; 64]; + final_block[0] = 0x80; + final_block[56..].copy_from_slice(&(8u64 * 64).to_be_bytes()); + + let mut state = INITIAL_STATE; + compress(&mut state, &[first_block, final_block]); + + let mut hash = String::new(); + for word in &state { + write!(hash, "{:08x}", word).expect("writing to String doesn't fail"); + } + assert_eq!(hash, "1b2293d21b17a0cb0c18737307c37333dea775eded18cefed45e50389f9f8184"); +} + +/// Tests each SHA256 intrinsic against fixed test vectors, generated by running the intrinsics +/// on aarch64 hardware. +#[target_feature(enable = "sha2")] +unsafe fn test_sha256_vectors() { + // vsha256hq_u32: (abcd, efgh, wk, expected) + const SHA256H_VECTORS: [([u32; 4], [u32; 4], [u32; 4], [u32; 4]); 3] = [ + ( + [0xd4db8ed5, 0x576d25e9, 0x46cefe6d, 0x0ea36724], + [0xfb8601ee, 0x496dd1d0, 0xd7b50546, 0xe42ab8a4], + [0xf02f3ed2, 0xa1c15350, 0x61ae31bf, 0x9f10088d], + [0xc64830e0, 0xe3226415, 0xa266428c, 0x2b335e17], + ), + ( + [0xead1ca07, 0x16264b71, 0xbcf9ffd6, 0xcc57fcd4], + [0xd06b54f2, 0x04262adc, 0x665c10cc, 0xe1c27002], + [0x18081d4b, 0x1825b05e, 0x1c99551d, 0xb91f4d2c], + [0x6e9a5cc0, 0xc5fd28ba, 0x48086f7f, 0x2d476e75], + ), + ( + [0xb281d803, 0xad5a30ff, 0x629303da, 0x02bb7a50], + [0x4042f60b, 0x6603a2b5, 0xdc21ac7b, 0x08c621e7], + [0x72dead87, 0xdfcbe2bb, 0x1a1e24b9, 0x5c8954c2], + [0xe0ccd4a0, 0x203a0366, 0x80076142, 0xf34b7da4], + ), + ]; + for (abcd, efgh, wk, expected) in SHA256H_VECTORS { + let res = vsha256hq_u32( + vld1q_u32(abcd.as_ptr()), + vld1q_u32(efgh.as_ptr()), + vld1q_u32(wk.as_ptr()), + ); + let mut out = [0u32; 4]; + vst1q_u32(out.as_mut_ptr(), res); + assert_eq!(out, expected); + } + + // vsha256h2q_u32: (efgh, abcd, wk, expected) + const SHA256H2_VECTORS: [([u32; 4], [u32; 4], [u32; 4], [u32; 4]); 3] = [ + ( + [0xd383961f, 0xb3e663ff, 0xf94805bc, 0xd1835c2e], + [0xb4ce4e8f, 0x6faf7a12, 0xb741db84, 0x772e35a5], + [0xb3c29b90, 0xdc6e64ec, 0x3db61cb9, 0xd939232c], + [0xb1fed2c6, 0x47318508, 0x375d3cf0, 0x35bda2e5], + ), + ( + [0xfebcb520, 0xa38b2a33, 0x87fbde8e, 0x51e6a1ff], + [0x9efc2493, 0x46a0d98a, 0x700e1ef1, 0xfdceb5c2], + [0x02e8475a, 0xcda6aebf, 0xa2e0c345, 0x8e2042a5], + [0xfcd8c86a, 0x9952c11e, 0xa6ad8642, 0x7028bf06], + ), + ( + [0xe21087a3, 0xd465f5cb, 0xc06435f9, 0x1d9382c3], + [0x26911c60, 0xe13c8858, 0x8f2aa6b1, 0x78ab965f], + [0xc426a92c, 0x7e5d190d, 0x2729339a, 0xf7425f03], + [0x95815de7, 0xec08aea7, 0x46607ac0, 0x8e824a28], + ), + ]; + for (efgh, abcd, wk, expected) in SHA256H2_VECTORS { + let res = vsha256h2q_u32( + vld1q_u32(efgh.as_ptr()), + vld1q_u32(abcd.as_ptr()), + vld1q_u32(wk.as_ptr()), + ); + let mut out = [0u32; 4]; + vst1q_u32(out.as_mut_ptr(), res); + assert_eq!(out, expected); + } + + // vsha256su0q_u32: (w0_3, w4_7, expected) + const SHA256SU0_VECTORS: [([u32; 4], [u32; 4], [u32; 4]); 3] = [ + ( + [0x2b258b3a, 0x47b86a0e, 0xa24dc5c1, 0xcb242640], + [0x1caea27b, 0xf56459d7, 0xb9183fa8, 0x340f42c5], + [0x3a2177b5, 0x2e35b5ae, 0x33b0c40e, 0x28567460], + ), + ( + [0xe153c4e4, 0x43e7c1a3, 0x16a9da20, 0xe8c76b0d], + [0xa213d54a, 0xc906cfda, 0x63085385, 0x5860e5a5], + [0x9fe7ac32, 0x78582efd, 0xf2b3f3a6, 0x5d1c6094], + ), + ( + [0x82a7f76b, 0x905f8107, 0xb4fc93bd, 0x0ff68a2b], + [0x054f4753, 0xdf38ef91, 0x4c9a6433, 0x15ef86a3], + [0x8012a2a0, 0xd9788776, 0xaa689369, 0x876e4162], + ), + ]; + for (w0_3, w4_7, expected) in SHA256SU0_VECTORS { + let res = vsha256su0q_u32(vld1q_u32(w0_3.as_ptr()), vld1q_u32(w4_7.as_ptr())); + let mut out = [0u32; 4]; + vst1q_u32(out.as_mut_ptr(), res); + assert_eq!(out, expected); + } + + // vsha256su1q_u32: (tw0_3, w8_11, w12_15, expected) + const SHA256SU1_VECTORS: [([u32; 4], [u32; 4], [u32; 4], [u32; 4]); 3] = [ + ( + [0xac8374e7, 0xee4609df, 0x03680814, 0xe6db8de0], + [0x036f8b47, 0x5d185ab6, 0xab1a1045, 0x0af3de89], + [0x22875a68, 0x75adbd3f, 0xee2a3408, 0x1f6deaf1], + [0x665aaffa, 0xe1819145, 0x1077cfea, 0x041514dc], + ), + ( + [0x41faecd0, 0xa7b39c4e, 0xd80abbd6, 0x1faafdd3], + [0x6612e79f, 0x2ebc512f, 0x851168cb, 0xfe506d3f], + [0xc1f991a0, 0xa7148ac6, 0xd1f9aa4f, 0xedb21a9c], + [0x5111aaa8, 0x7aeb8d02, 0xb6708fd5, 0x98e4583e], + ), + ( + [0x518563cc, 0xa7dea3da, 0x038d7c62, 0x26e55666], + [0x02180e54, 0x14f6cfbc, 0xb9e310cd, 0x65572094], + [0xfc725e1c, 0x71c954da, 0xaf9700ff, 0xb4f8d736], + [0xc6c7fb81, 0xd312677d, 0x6b66073b, 0xa2bd4bf4], + ), + ]; + for (tw0_3, w8_11, w12_15, expected) in SHA256SU1_VECTORS { + let res = vsha256su1q_u32( + vld1q_u32(tw0_3.as_ptr()), + vld1q_u32(w8_11.as_ptr()), + vld1q_u32(w12_15.as_ptr()), + ); + let mut out = [0u32; 4]; + vst1q_u32(out.as_mut_ptr(), res); + assert_eq!(out, expected); + } +} + +// `K32` and `compress` below are copied from RustCrypto: +// https://github.com/RustCrypto/hashes/blob/3d2bc57db40fd6aeb25d6c6da98d67e2784c2985/sha2/src/consts.rs +// https://github.com/RustCrypto/hashes/blob/3d2bc57db40fd6aeb25d6c6da98d67e2784c2985/sha2/src/sha256/aarch64_sha2.rs + +/// Round constants for SHA-256 family of digests +static K32: [u32; 64] = [ + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, +]; + +#[target_feature(enable = "sha2")] +unsafe fn compress(state: &mut [u32; 8], blocks: &[[u8; 64]]) { + // SAFETY: Requires the sha2 feature. + + // Load state into vectors. + let mut abcd = vld1q_u32(state[0..4].as_ptr()); + let mut efgh = vld1q_u32(state[4..8].as_ptr()); + + // Iterate through the message blocks. + for block in blocks { + // Keep original state values. + let abcd_orig = abcd; + let efgh_orig = efgh; + + // Load the message block into vectors, assuming little endianness. + let mut s0 = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(block[0..16].as_ptr()))); + let mut s1 = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(block[16..32].as_ptr()))); + let mut s2 = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(block[32..48].as_ptr()))); + let mut s3 = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(block[48..64].as_ptr()))); + + // Rounds 0 to 3 + let mut tmp = vaddq_u32(s0, vld1q_u32(K32[0..4].as_ptr())); + let mut abcd_prev = abcd; + abcd = vsha256hq_u32(abcd_prev, efgh, tmp); + efgh = vsha256h2q_u32(efgh, abcd_prev, tmp); + + // Rounds 4 to 7 + tmp = vaddq_u32(s1, vld1q_u32(K32[4..8].as_ptr())); + abcd_prev = abcd; + abcd = vsha256hq_u32(abcd_prev, efgh, tmp); + efgh = vsha256h2q_u32(efgh, abcd_prev, tmp); + + // Rounds 8 to 11 + tmp = vaddq_u32(s2, vld1q_u32(K32[8..12].as_ptr())); + abcd_prev = abcd; + abcd = vsha256hq_u32(abcd_prev, efgh, tmp); + efgh = vsha256h2q_u32(efgh, abcd_prev, tmp); + + // Rounds 12 to 15 + tmp = vaddq_u32(s3, vld1q_u32(K32[12..16].as_ptr())); + abcd_prev = abcd; + abcd = vsha256hq_u32(abcd_prev, efgh, tmp); + efgh = vsha256h2q_u32(efgh, abcd_prev, tmp); + + for t in (16..64).step_by(16) { + // Rounds t to t + 3 + s0 = vsha256su1q_u32(vsha256su0q_u32(s0, s1), s2, s3); + tmp = vaddq_u32(s0, vld1q_u32(K32[t..t + 4].as_ptr())); + abcd_prev = abcd; + abcd = vsha256hq_u32(abcd_prev, efgh, tmp); + efgh = vsha256h2q_u32(efgh, abcd_prev, tmp); + + // Rounds t + 4 to t + 7 + s1 = vsha256su1q_u32(vsha256su0q_u32(s1, s2), s3, s0); + tmp = vaddq_u32(s1, vld1q_u32(K32[t + 4..t + 8].as_ptr())); + abcd_prev = abcd; + abcd = vsha256hq_u32(abcd_prev, efgh, tmp); + efgh = vsha256h2q_u32(efgh, abcd_prev, tmp); + + // Rounds t + 8 to t + 11 + s2 = vsha256su1q_u32(vsha256su0q_u32(s2, s3), s0, s1); + tmp = vaddq_u32(s2, vld1q_u32(K32[t + 8..t + 12].as_ptr())); + abcd_prev = abcd; + abcd = vsha256hq_u32(abcd_prev, efgh, tmp); + efgh = vsha256h2q_u32(efgh, abcd_prev, tmp); + + // Rounds t + 12 to t + 15 + s3 = vsha256su1q_u32(vsha256su0q_u32(s3, s0), s1, s2); + tmp = vaddq_u32(s3, vld1q_u32(K32[t + 12..t + 16].as_ptr())); + abcd_prev = abcd; + abcd = vsha256hq_u32(abcd_prev, efgh, tmp); + efgh = vsha256h2q_u32(efgh, abcd_prev, tmp); + } + + // Add the block-specific state to the original state. + abcd = vaddq_u32(abcd, abcd_orig); + efgh = vaddq_u32(efgh, efgh_orig); + } + + // Store vectors into state. + vst1q_u32(state[0..4].as_mut_ptr(), abcd); + vst1q_u32(state[4..8].as_mut_ptr(), efgh); +} From 856278b4ecb924db3fc9637df797dcb8f010cb65 Mon Sep 17 00:00:00 2001 From: jrakibi Date: Sun, 12 Jul 2026 17:49:21 +0800 Subject: [PATCH 16/23] x86/sha: drop "reg" from variable names Matches the naming already used in the aarch64 SHA256 shims. --- src/tools/miri/src/intrinsics/x86/sha.rs | 32 ++++++++++++------------ 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/tools/miri/src/intrinsics/x86/sha.rs b/src/tools/miri/src/intrinsics/x86/sha.rs index d7f17c8d6e383..23ee13c09a68b 100644 --- a/src/tools/miri/src/intrinsics/x86/sha.rs +++ b/src/tools/miri/src/intrinsics/x86/sha.rs @@ -22,12 +22,12 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Prefix should have already been checked. let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.sha").unwrap(); - fn read<'c>(ecx: &mut MiriInterpCx<'c>, reg: &OpTy<'c>) -> InterpResult<'c, [u32; 4]> { + fn read<'c>(ecx: &mut MiriInterpCx<'c>, vec: &OpTy<'c>) -> InterpResult<'c, [u32; 4]> { let mut res = [0; 4]; // We reverse the order because x86 is little endian but the copied implementation uses // big endian. for (i, dst) in res.iter_mut().rev().enumerate() { - let projected = &ecx.project_index(reg, i.try_into().unwrap())?; + let projected = &ecx.project_index(vec, i.try_into().unwrap())?; *dst = ecx.read_scalar(projected)?.to_u32()? } interp_ok(res) @@ -52,9 +52,9 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "256rnds2" => { let [a, b, k] = this.check_shim_sig_unadjusted(link_name, args)?; - let (a_reg, a_len) = this.project_to_simd(a)?; - let (b_reg, b_len) = this.project_to_simd(b)?; - let (k_reg, k_len) = this.project_to_simd(k)?; + let (a, a_len) = this.project_to_simd(a)?; + let (b, b_len) = this.project_to_simd(b)?; + let (k, k_len) = this.project_to_simd(k)?; let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(a_len, 4); @@ -62,9 +62,9 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { assert_eq!(k_len, 4); assert_eq!(dest_len, 4); - let a = read(this, &a_reg)?; - let b = read(this, &b_reg)?; - let k = read(this, &k_reg)?; + let a = read(this, &a)?; + let b = read(this, &b)?; + let k = read(this, &k)?; let result = sha256_digest_round_x2(a, b, k); write(this, &dest, result)?; @@ -73,16 +73,16 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "256msg1" => { let [a, b] = this.check_shim_sig_unadjusted(link_name, args)?; - let (a_reg, a_len) = this.project_to_simd(a)?; - let (b_reg, b_len) = this.project_to_simd(b)?; + let (a, a_len) = this.project_to_simd(a)?; + let (b, b_len) = this.project_to_simd(b)?; let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(a_len, 4); assert_eq!(b_len, 4); assert_eq!(dest_len, 4); - let a = read(this, &a_reg)?; - let b = read(this, &b_reg)?; + let a = read(this, &a)?; + let b = read(this, &b)?; let result = sha256msg1(a, b); write(this, &dest, result)?; @@ -91,16 +91,16 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "256msg2" => { let [a, b] = this.check_shim_sig_unadjusted(link_name, args)?; - let (a_reg, a_len) = this.project_to_simd(a)?; - let (b_reg, b_len) = this.project_to_simd(b)?; + let (a, a_len) = this.project_to_simd(a)?; + let (b, b_len) = this.project_to_simd(b)?; let (dest, dest_len) = this.project_to_simd(dest)?; assert_eq!(a_len, 4); assert_eq!(b_len, 4); assert_eq!(dest_len, 4); - let a = read(this, &a_reg)?; - let b = read(this, &b_reg)?; + let a = read(this, &a)?; + let b = read(this, &b)?; let result = sha256msg2(a, b); write(this, &dest, result)?; From c72ad96bc4f5f487d60cd3095e9cb1b9973b2bab Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Wed, 29 Jul 2026 05:27:40 +0000 Subject: [PATCH 17/23] Prepare for merging from rust-lang/rust This updates the rust-version file to 701a6513a48eac30d49110ba06187648b7553622. --- 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 5a25584457ac8..6adf22ffd1418 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -d3ea0356830dc019038110eba0bc8f790aaef2e4 +701a6513a48eac30d49110ba06187648b7553622 From 939e545d68a56da072a0b00a51a8280fb5a2627e Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Sat, 1 Aug 2026 05:28:39 +0000 Subject: [PATCH 18/23] Prepare for merging from rust-lang/rust This updates the rust-version file to cb9d1b0640549f1b041aae430dc413ce93f8c204. --- 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 6adf22ffd1418..f2145e31b58c5 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -701a6513a48eac30d49110ba06187648b7553622 +cb9d1b0640549f1b041aae430dc413ce93f8c204 From d529bff024775c09f19e37a7755042541590e5cf Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Sat, 1 Aug 2026 05:34:04 +0000 Subject: [PATCH 19/23] fmt --- src/tools/miri/src/shims/unix/fs.rs | 11 ++---- src/tools/miri/tests/pass-dep/libc/libc-fs.rs | 1 + .../tests/pass-dep/libc/pthread-threadname.rs | 37 +++++++------------ src/tools/miri/tests/pass-dep/shims/gettid.rs | 20 +++------- 4 files changed, 23 insertions(+), 46 deletions(-) diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index b637f64b80514..f5e7aad0a140f 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -1790,15 +1790,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fopts.read(true).write(true).create_new(true); cfg_select! { - unix => - { + unix => { use std::os::unix::fs::OpenOptionsExt; // Do not allow others to read or modify this file. fopts.mode(0o600); fopts.custom_flags(libc::O_EXCL); } - windows => - { + windows => { use std::os::windows::fs::OpenOptionsExt; // Do not allow others to read or modify this file. fopts.share_mode(0); @@ -1992,8 +1990,7 @@ impl FileMetadata { cfg_select! { unix => { - use std::os::unix::fs::MetadataExt; - use std::os::unix::fs::PermissionsExt; + use std::os::unix::fs::{MetadataExt, PermissionsExt}; let dev = metadata.dev(); let ino = metadata.ino(); @@ -2038,7 +2035,7 @@ impl FileMetadata { blksize: None, blocks: None, })) - }, + } } } } 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 3c11d0f38e17a..e8d2b111c3d1a 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs @@ -1006,6 +1006,7 @@ fn test_readdir() { target_os = "macos" => { // On macos we only support readdir_r as that's what std uses there. use std::mem::MaybeUninit; + use libc::dirent; let mut entry: MaybeUninit = MaybeUninit::uninit(); let mut result: *mut dirent = std::ptr::null_mut(); diff --git a/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs b/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs index 6cba672c6569c..1c33cb266f514 100644 --- a/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs +++ b/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs @@ -5,12 +5,8 @@ use std::thread; const MAX_THREAD_NAME_LEN: usize = { cfg_select! { - target_os = "linux" => { - 16 - } - any(target_os = "illumos", target_os = "solaris") => { - 32 - } + target_os = "linux" => 16, + any(target_os = "illumos", target_os = "solaris") => 32, target_os = "macos" => { libc::MAXTHREADNAMESIZE // 64, at the time of writing } @@ -38,12 +34,8 @@ fn main() { target_os = "freebsd", target_os = "illumos", target_os = "solaris" - ) => { - unsafe { libc::pthread_setname_np(libc::pthread_self(), name.as_ptr().cast()) } - } - target_os = "macos" => { - unsafe { libc::pthread_setname_np(name.as_ptr().cast()) } - } + ) => unsafe { libc::pthread_setname_np(libc::pthread_self(), name.as_ptr().cast()) }, + target_os = "macos" => unsafe { libc::pthread_setname_np(name.as_ptr().cast()) }, _ => { compile_error!("set_thread_name not supported for this OS") } @@ -58,11 +50,9 @@ fn main() { target_os = "illumos", target_os = "solaris", target_os = "macos" - ) => { - unsafe { - libc::pthread_getname_np(libc::pthread_self(), name.as_mut_ptr().cast(), name.len()) - } - } + ) => unsafe { + libc::pthread_getname_np(libc::pthread_self(), name.as_mut_ptr().cast(), name.len()) + }, _ => { compile_error!("get_thread_name not supported for this OS") } @@ -197,7 +187,10 @@ fn main() { // too short for the thread name -- they truncate instead. assert_eq!(res, 0); let cstr = CStr::from_bytes_until_nul(&buf).unwrap(); - assert_eq!(cstr.to_bytes(), &truncated_name.as_bytes()[..(truncated_name.len() - 1)]); + assert_eq!( + cstr.to_bytes(), + &truncated_name.as_bytes()[..(truncated_name.len() - 1)] + ); } _ => { // The rest should give an error. @@ -213,12 +206,8 @@ fn main() { let invalid_thread = 0xdeadbeef; let error = { cfg_select! { - target_os = "linux" => { - libc::ENOENT - } - _ => { - libc::ESRCH - } + target_os = "linux" => libc::ENOENT, + _ => libc::ESRCH, } }; diff --git a/src/tools/miri/tests/pass-dep/shims/gettid.rs b/src/tools/miri/tests/pass-dep/shims/gettid.rs index 05885ac277f76..2522a15219148 100644 --- a/src/tools/miri/tests/pass-dep/shims/gettid.rs +++ b/src/tools/miri/tests/pass-dep/shims/gettid.rs @@ -6,21 +6,11 @@ fn gettid() -> u64 { cfg_select! { - any(target_os = "android", target_os = "linux") => { - gettid_linux_like() - } - any(target_os = "nto", target_os = "qnx") => { - unsafe { libc::gettid() as u64 } - } - target_os = "openbsd" => { - unsafe { libc::getthrid() as u64 } - } - target_os = "freebsd" => { - unsafe { libc::pthread_getthreadid_np() as u64 } - } - target_os = "netbsd" => { - unsafe { libc::_lwp_self() as u64 } - } + any(target_os = "android", target_os = "linux") => gettid_linux_like(), + any(target_os = "nto", target_os = "qnx") => unsafe { libc::gettid() as u64 }, + target_os = "openbsd" => unsafe { libc::getthrid() as u64 }, + target_os = "freebsd" => unsafe { libc::pthread_getthreadid_np() as u64 }, + target_os = "netbsd" => unsafe { libc::_lwp_self() as u64 }, any(target_os = "solaris", target_os = "illumos") => { // On Solaris and Illumos, the `pthread_t` is the OS TID. unsafe { libc::pthread_self() as u64 } From c9d77c973dc5a40a865a318b3c1d71cd02403d24 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 1 Aug 2026 10:56:05 +0200 Subject: [PATCH 20/23] show clear error when encountering an argfile --- src/tools/miri/cargo-miri/src/phases.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs index 426317a5452aa..50a0f671aca4d 100644 --- a/src/tools/miri/cargo-miri/src/phases.rs +++ b/src/tools/miri/cargo-miri/src/phases.rs @@ -342,6 +342,16 @@ pub fn phase_rustc(args: impl Iterator, phase: RustcPhase) { } } + // Ensure we show an error if we encounter an argfile, rather than randomly misbehvaing. + // We know rustdoc doesn't put anything important in the argfiles so we can ignore them there. + let args = args.inspect(|arg| { + if phase != RustcPhase::Rustdoc && arg.starts_with('@') { + show_error!( + "cargo uses an argfile to invoke rustc, which is not supported by cargo-miri" + ) + } + }); + let verbose = env::var("MIRI_VERBOSE") .map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer")); let target_crate = is_target_crate(); From b72b8490c4438043295be386ddf8c4717d8215d2 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Sun, 2 Aug 2026 05:28:20 +0000 Subject: [PATCH 21/23] Prepare for merging from rust-lang/rust This updates the rust-version file to 73dc9167f1cd099e525c9ade2e068d1907b78564. --- 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 f2145e31b58c5..2f35beeceda8c 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -cb9d1b0640549f1b041aae430dc413ce93f8c204 +73dc9167f1cd099e525c9ade2e068d1907b78564 From 937dfd4ea135a03a271afc7f878314b313a2d067 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Sun, 2 Aug 2026 05:33:33 +0000 Subject: [PATCH 22/23] fmt --- src/tools/miri/src/concurrency/sync.rs | 12 ++++++++++-- .../tests/fail/validity/cast_fn_ptr_invalid.rs | 2 +- .../fail/validity/cast_raw_ptr_invalid_vtable.rs | 16 ++++++---------- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/tools/miri/src/concurrency/sync.rs b/src/tools/miri/src/concurrency/sync.rs index a366805289227..f81408dc1f79b 100644 --- a/src/tools/miri/src/concurrency/sync.rs +++ b/src/tools/miri/src/concurrency/sync.rs @@ -339,7 +339,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { { assert!(init_val != uninit_val); let this = self.eval_context_mut(); - this.check_ptr_access(obj.ptr(), obj.layout.size, CheckInAllocMsg::Dereferenceable("pointer"))?; + this.check_ptr_access( + obj.ptr(), + obj.layout.size, + CheckInAllocMsg::Dereferenceable("pointer"), + )?; assert!(init_offset < obj.layout.size); // ensure our 1-byte flag fits let init_field = obj.offset(init_offset, this.machine.layouts.u8, this)?; @@ -389,7 +393,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { 'tcx: 'a, { let this = self.eval_context_mut(); - this.check_ptr_access(obj.ptr(), obj.layout.size, CheckInAllocMsg::Dereferenceable("pointer"))?; + this.check_ptr_access( + obj.ptr(), + obj.layout.size, + CheckInAllocMsg::Dereferenceable("pointer"), + )?; assert!(init_offset < obj.layout.size); // ensure our 1-byte flag fits let init_field = obj.offset(init_offset, this.machine.layouts.u8, this)?; diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid.rs b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid.rs index b892c1155cfeb..4c245a1146b1e 100644 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid.rs +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid.rs @@ -18,7 +18,7 @@ fn test(ptr: fn(), overwrite: fn(&mut fn())) { ptrptr = &mut ptr; Call(_unused = overwrite(ptrptr), ReturnTo(ret), UnwindContinue()) } - + ret = { ptr2 = ptr as *mut u8; //~ERROR: does not point to a function Return() diff --git a/src/tools/miri/tests/fail/validity/cast_raw_ptr_invalid_vtable.rs b/src/tools/miri/tests/fail/validity/cast_raw_ptr_invalid_vtable.rs index 4e0fe29257e31..de7edef1370dc 100644 --- a/src/tools/miri/tests/fail/validity/cast_raw_ptr_invalid_vtable.rs +++ b/src/tools/miri/tests/fail/validity/cast_raw_ptr_invalid_vtable.rs @@ -17,7 +17,7 @@ fn test(ptr: *const T, data: U, overwrite: fn(&mut *const T, U)) { ptrptr = &mut ptr; Call(_unused = overwrite(ptrptr, data), ReturnTo(ret), UnwindContinue()) } - + ret = { ptr2 = CastPtrToPtr(ptr); //~ERROR: vtable for `std::fmt::Debug` but `std::fmt::Display` was expected Return() @@ -35,13 +35,9 @@ fn main() { let x = S { f: 0, g: 0 }; let ptr1: *const S = &x; let ptr2: *const S = &x; - test::, _>( - ptr2, - ptr1, - |ptrptr2, ptr1| unsafe { - // Give ptr2 the vtable from ptr1. - let ptrptr2 = std::ptr::from_mut(ptrptr2); - ptrptr2.copy_from(&raw const ptr1 as *const _, 1) ; - } - ); + test::, _>(ptr2, ptr1, |ptrptr2, ptr1| unsafe { + // Give ptr2 the vtable from ptr1. + let ptrptr2 = std::ptr::from_mut(ptrptr2); + ptrptr2.copy_from(&raw const ptr1 as *const _, 1); + }); } From b488a9062821aa07045875a552a428be4a15879a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 2 Aug 2026 09:33:09 +0200 Subject: [PATCH 23/23] update genmc spinloop test output --- .../tests/genmc/pass/shims/spinloop_assume.replaced123.stderr | 4 ++-- .../tests/genmc/pass/shims/spinloop_assume.replaced321.stderr | 4 ++-- src/tools/miri/tests/genmc/pass/shims/spinloop_assume.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/tools/miri/tests/genmc/pass/shims/spinloop_assume.replaced123.stderr b/src/tools/miri/tests/genmc/pass/shims/spinloop_assume.replaced123.stderr index c79a87b33a5f5..c57aeb93ed1f3 100644 --- a/src/tools/miri/tests/genmc/pass/shims/spinloop_assume.replaced123.stderr +++ b/src/tools/miri/tests/genmc/pass/shims/spinloop_assume.replaced123.stderr @@ -1,5 +1,5 @@ Running GenMC Verification... -Verification complete with 9 executions. No errors found. +Verification complete with 3 executions. No errors found. Number of complete executions explored: 1 -Number of blocked executions seen: 8 +Number of blocked executions seen: 2 Verification took [TIME]s. diff --git a/src/tools/miri/tests/genmc/pass/shims/spinloop_assume.replaced321.stderr b/src/tools/miri/tests/genmc/pass/shims/spinloop_assume.replaced321.stderr index c79a87b33a5f5..472332d719f24 100644 --- a/src/tools/miri/tests/genmc/pass/shims/spinloop_assume.replaced321.stderr +++ b/src/tools/miri/tests/genmc/pass/shims/spinloop_assume.replaced321.stderr @@ -1,5 +1,5 @@ Running GenMC Verification... -Verification complete with 9 executions. No errors found. +Verification complete with 4 executions. No errors found. Number of complete executions explored: 1 -Number of blocked executions seen: 8 +Number of blocked executions seen: 3 Verification took [TIME]s. diff --git a/src/tools/miri/tests/genmc/pass/shims/spinloop_assume.rs b/src/tools/miri/tests/genmc/pass/shims/spinloop_assume.rs index 5a4d05370cfcd..1b5c43959f85a 100644 --- a/src/tools/miri/tests/genmc/pass/shims/spinloop_assume.rs +++ b/src/tools/miri/tests/genmc/pass/shims/spinloop_assume.rs @@ -50,7 +50,7 @@ fn spin_until(value: u64) { unsafe { miri_genmc_assume(false) }; } -#[cfg(not(any(bounded123, bounded321)))] +#[cfg(any(replaced123, replaced321))] /// For full replacement, we limit it to only 1 load. fn spin_until(value: u64) { unsafe { miri_genmc_assume(FLAG.load(Acquire) == value) };