Skip to content

Commit 6f9c6e1

Browse files
authored
Rollup merge of #124251 - scottmcm:unop-ptr-metadata, r=oli-obk
Add an intrinsic for `ptr::metadata` The follow-up to #123840, so we can remove `PtrComponents` and `PtrRepr` from libcore entirely (well, after a bootstrap update). As discussed in <https://rust-lang.zulipchat.com/#narrow/stream/189540-t-compiler.2Fwg-mir-opt/topic/.60ptr_metadata.60.20in.20MIR/near/435637808>, this introduces `UnOp::PtrMetadata` taking a raw pointer and returning the associated metadata value. By no longer going through a `union`, this should also help future PRs better optimize pointer operations. r? ``@oli-obk``
2 parents 59bbd30 + e0f1d8e commit 6f9c6e1

7 files changed

+149
-1
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//@compile-flags: -Zmiri-disable-validation
2+
#![feature(core_intrinsics, custom_mir)]
3+
use std::intrinsics::mir::*;
4+
5+
// This disables validation and uses custom MIR hit exactly the UB in the intrinsic,
6+
// rather than getting UB from the typed load or parameter passing.
7+
8+
#[custom_mir(dialect = "runtime")]
9+
pub unsafe fn deref_meta(p: *const *const [i32]) -> usize {
10+
mir!({
11+
RET = PtrMetadata(*p); //~ ERROR: Undefined Behavior: using uninitialized data
12+
Return()
13+
})
14+
}
15+
16+
fn main() {
17+
let mut p = std::mem::MaybeUninit::<*const [i32]>::uninit();
18+
unsafe {
19+
(*p.as_mut_ptr().cast::<[usize; 2]>())[1] = 4;
20+
let _meta = deref_meta(p.as_ptr().cast());
21+
}
22+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
2+
--> $DIR/ptr_metadata_uninit_slice_data.rs:LL:CC
3+
|
4+
LL | RET = PtrMetadata(*p);
5+
| ^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
6+
|
7+
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
8+
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
9+
= note: BACKTRACE:
10+
= note: inside `deref_meta` at $DIR/ptr_metadata_uninit_slice_data.rs:LL:CC
11+
note: inside `main`
12+
--> $DIR/ptr_metadata_uninit_slice_data.rs:LL:CC
13+
|
14+
LL | let _meta = deref_meta(p.as_ptr().cast());
15+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
16+
17+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
18+
19+
error: aborting due to 1 previous error
20+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//@compile-flags: -Zmiri-disable-validation
2+
#![feature(core_intrinsics, custom_mir)]
3+
use std::intrinsics::mir::*;
4+
5+
// This disables validation and uses custom MIR hit exactly the UB in the intrinsic,
6+
// rather than getting UB from the typed load or parameter passing.
7+
8+
#[custom_mir(dialect = "runtime")]
9+
pub unsafe fn deref_meta(p: *const *const [i32]) -> usize {
10+
mir!({
11+
RET = PtrMetadata(*p); //~ ERROR: Undefined Behavior: using uninitialized data
12+
Return()
13+
})
14+
}
15+
16+
fn main() {
17+
let mut p = std::mem::MaybeUninit::<*const [i32]>::uninit();
18+
unsafe {
19+
(*p.as_mut_ptr().cast::<[*const i32; 2]>())[0] = 4 as *const i32;
20+
let _meta = deref_meta(p.as_ptr().cast());
21+
}
22+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
warning: integer-to-pointer cast
2+
--> $DIR/ptr_metadata_uninit_slice_len.rs:LL:CC
3+
|
4+
LL | (*p.as_mut_ptr().cast::<[*const i32; 2]>())[0] = 4 as *const i32;
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast
6+
|
7+
= help: This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`,
8+
= help: which means that Miri might miss pointer bugs in this program.
9+
= help: See https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation.
10+
= help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead.
11+
= help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `with_exposed_provenance` semantics.
12+
= help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning.
13+
= note: BACKTRACE:
14+
= note: inside `main` at $DIR/ptr_metadata_uninit_slice_len.rs:LL:CC
15+
16+
error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
17+
--> $DIR/ptr_metadata_uninit_slice_len.rs:LL:CC
18+
|
19+
LL | RET = PtrMetadata(*p);
20+
| ^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
21+
|
22+
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
23+
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
24+
= note: BACKTRACE:
25+
= note: inside `deref_meta` at $DIR/ptr_metadata_uninit_slice_len.rs:LL:CC
26+
note: inside `main`
27+
--> $DIR/ptr_metadata_uninit_slice_len.rs:LL:CC
28+
|
29+
LL | let _meta = deref_meta(p.as_ptr().cast());
30+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
31+
32+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
33+
34+
error: aborting due to 1 previous error; 1 warning emitted
35+
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//@compile-flags: -Zmiri-disable-validation
2+
#![feature(core_intrinsics, custom_mir)]
3+
use std::intrinsics::mir::*;
4+
5+
// This disables validation and uses custom MIR hit exactly the UB in the intrinsic,
6+
// rather than getting UB from the typed load or parameter passing.
7+
8+
#[custom_mir(dialect = "runtime")]
9+
pub unsafe fn deref_meta(p: *const *const i32) -> () {
10+
mir!({
11+
RET = PtrMetadata(*p); //~ ERROR: Undefined Behavior: using uninitialized data
12+
Return()
13+
})
14+
}
15+
16+
fn main() {
17+
// Even though the meta is the trivially-valid `()`, this is still UB
18+
19+
let p = std::mem::MaybeUninit::<*const i32>::uninit();
20+
unsafe {
21+
let _meta = deref_meta(p.as_ptr());
22+
}
23+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
2+
--> $DIR/ptr_metadata_uninit_thin.rs:LL:CC
3+
|
4+
LL | RET = PtrMetadata(*p);
5+
| ^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
6+
|
7+
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
8+
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
9+
= note: BACKTRACE:
10+
= note: inside `deref_meta` at $DIR/ptr_metadata_uninit_thin.rs:LL:CC
11+
note: inside `main`
12+
--> $DIR/ptr_metadata_uninit_thin.rs:LL:CC
13+
|
14+
LL | let _meta = deref_meta(p.as_ptr());
15+
| ^^^^^^^^^^^^^^^^^^^^^^
16+
17+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
18+
19+
error: aborting due to 1 previous error
20+

tests/pass/intrinsics/intrinsics.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//@compile-flags: -Zmiri-permissive-provenance
2-
#![feature(core_intrinsics, layout_for_ptr)]
2+
#![feature(core_intrinsics, layout_for_ptr, ptr_metadata)]
33
//! Tests for various intrinsics that do not fit anywhere else.
44
55
use std::intrinsics;
@@ -57,4 +57,10 @@ fn main() {
5757
// Make sure that even if the discriminant is stored together with data, the intrinsic returns
5858
// only the discriminant, nothing about the data.
5959
assert_eq!(discriminant(&Some(false)), discriminant(&Some(true)));
60+
61+
let () = intrinsics::ptr_metadata(&[1, 2, 3]);
62+
let len = intrinsics::ptr_metadata(&[1, 2, 3][..]);
63+
assert_eq!(len, 3);
64+
let dyn_meta = intrinsics::ptr_metadata(&[1, 2, 3] as &dyn std::fmt::Debug);
65+
assert_eq!(dyn_meta.size_of(), 12);
6066
}

0 commit comments

Comments
 (0)