Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit a4a083e

Browse files
committedNov 12, 2023
miri: support 'promising' alignment for symbolic alignment check
1 parent a04d56b commit a4a083e

File tree

11 files changed

+232
-110
lines changed

11 files changed

+232
-110
lines changed
 

‎compiler/rustc_const_eval/src/interpret/machine.rs

+15-14
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ use rustc_middle::mir;
1212
use rustc_middle::ty::layout::TyAndLayout;
1313
use rustc_middle::ty::{self, TyCtxt};
1414
use rustc_span::def_id::DefId;
15-
use rustc_target::abi::Size;
15+
use rustc_target::abi::{Align, Size};
1616
use rustc_target::spec::abi::Abi as CallAbi;
1717

1818
use super::{
19-
AllocBytes, AllocId, AllocRange, Allocation, ConstAllocation, FnArg, Frame, ImmTy, InterpCx,
20-
InterpResult, MPlaceTy, MemoryKind, OpTy, PlaceTy, Pointer, Provenance,
19+
AllocBytes, AllocId, AllocKind, AllocRange, Allocation, ConstAllocation, FnArg, Frame, ImmTy,
20+
InterpCx, InterpResult, MPlaceTy, MemoryKind, Misalignment, OpTy, PlaceTy, Pointer, Provenance,
2121
};
2222

2323
/// Data returned by Machine::stack_pop,
@@ -135,11 +135,18 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
135135
/// Whether memory accesses should be alignment-checked.
136136
fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
137137

138-
/// Whether, when checking alignment, we should look at the actual address and thus support
139-
/// custom alignment logic based on whatever the integer address happens to be.
140-
///
141-
/// If this returns true, Provenance::OFFSET_IS_ADDR must be true.
142-
fn use_addr_for_alignment_check(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
138+
/// Gives the machine a chance to detect more misalignment than the built-in checks would catch.
139+
#[inline(always)]
140+
fn alignment_check(
141+
_ecx: &InterpCx<'mir, 'tcx, Self>,
142+
_alloc_id: AllocId,
143+
_alloc_align: Align,
144+
_alloc_kind: AllocKind,
145+
_offset: Size,
146+
_align: Align,
147+
) -> Option<Misalignment> {
148+
None
149+
}
143150

144151
/// Whether to enforce the validity invariant for a specific layout.
145152
fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>, layout: TyAndLayout<'tcx>) -> bool;
@@ -511,12 +518,6 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
511518
type FrameExtra = ();
512519
type Bytes = Box<[u8]>;
513520

514-
#[inline(always)]
515-
fn use_addr_for_alignment_check(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
516-
// We do not support `use_addr`.
517-
false
518-
}
519-
520521
#[inline(always)]
521522
fn ignore_optional_overflow_checks(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
522523
false

‎compiler/rustc_const_eval/src/interpret/memory.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ impl<T: fmt::Display> fmt::Display for MemoryKind<T> {
5858
}
5959

6060
/// The return value of `get_alloc_info` indicates the "kind" of the allocation.
61+
#[derive(Copy, Clone, PartialEq, Debug)]
6162
pub enum AllocKind {
6263
/// A regular live data allocation.
6364
LiveData,
@@ -473,8 +474,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
473474
match self.ptr_try_get_alloc_id(ptr) {
474475
Err(addr) => offset_misalignment(addr, align),
475476
Ok((alloc_id, offset, _prov)) => {
476-
let (_size, alloc_align, _kind) = self.get_alloc_info(alloc_id);
477-
if M::use_addr_for_alignment_check(self) {
477+
let (_size, alloc_align, kind) = self.get_alloc_info(alloc_id);
478+
if let Some(misalign) =
479+
M::alignment_check(self, alloc_id, alloc_align, kind, offset, align)
480+
{
481+
Some(misalign)
482+
} else if M::Provenance::OFFSET_IS_ADDR {
478483
// `use_addr_for_alignment_check` can only be true if `OFFSET_IS_ADDR` is true.
479484
offset_misalignment(ptr.addr().bytes(), align)
480485
} else {

‎library/core/src/slice/mod.rs

+27
Original file line numberDiff line numberDiff line change
@@ -3876,6 +3876,18 @@ impl<T> [T] {
38763876
} else {
38773877
let (left, rest) = self.split_at(offset);
38783878
let (us_len, ts_len) = rest.align_to_offsets::<U>();
3879+
// Inform Miri that we want to consider the "middle" pointer to be suitably aligned.
3880+
#[cfg(miri)]
3881+
{
3882+
extern "Rust" {
3883+
pub fn miri_promise_symbolic_alignment(ptr: *const (), align: usize);
3884+
}
3885+
3886+
// SAFETY: the pointer is dereferenceable and the alignment a power of 2.
3887+
unsafe {
3888+
miri_promise_symbolic_alignment(rest.as_ptr().cast(), mem::align_of::<U>());
3889+
}
3890+
}
38793891
// SAFETY: now `rest` is definitely aligned, so `from_raw_parts` below is okay,
38803892
// since the caller guarantees that we can transmute `T` to `U` safely.
38813893
unsafe {
@@ -3946,6 +3958,21 @@ impl<T> [T] {
39463958
let (us_len, ts_len) = rest.align_to_offsets::<U>();
39473959
let rest_len = rest.len();
39483960
let mut_ptr = rest.as_mut_ptr();
3961+
// Inform Miri that we want to consider the "middle" pointer to be suitably aligned.
3962+
#[cfg(miri)]
3963+
{
3964+
extern "Rust" {
3965+
pub fn miri_promise_symbolic_alignment(ptr: *const (), align: usize);
3966+
}
3967+
3968+
// SAFETY: the pointer is dereferenceable and the alignment a power of 2.
3969+
unsafe {
3970+
miri_promise_symbolic_alignment(
3971+
mut_ptr.cast() as *const (),
3972+
mem::align_of::<U>(),
3973+
);
3974+
}
3975+
}
39493976
// We can't use `rest` again after this, that would invalidate its alias `mut_ptr`!
39503977
// SAFETY: see comments for `align_to`.
39513978
unsafe {

‎src/tools/miri/src/machine.rs

+51-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//! `Machine` trait.
33
44
use std::borrow::Cow;
5-
use std::cell::RefCell;
5+
use std::cell::{Cell, RefCell};
66
use std::fmt;
77
use std::path::Path;
88
use std::process;
@@ -309,11 +309,20 @@ pub struct AllocExtra<'tcx> {
309309
/// if this allocation is leakable. The backtrace is not
310310
/// pruned yet; that should be done before printing it.
311311
pub backtrace: Option<Vec<FrameInfo<'tcx>>>,
312+
/// An offset inside this allocation that was deemed aligned even for symbolic alignment checks.
313+
/// Invariant: the promised alignment will never be less than the native alignment of this allocation.
314+
pub symbolic_alignment: Cell<Option<(Size, Align)>>,
312315
}
313316

314317
impl VisitTags for AllocExtra<'_> {
315318
fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
316-
let AllocExtra { borrow_tracker, data_race, weak_memory, backtrace: _ } = self;
319+
let AllocExtra {
320+
borrow_tracker,
321+
data_race,
322+
weak_memory,
323+
backtrace: _,
324+
symbolic_alignment: _,
325+
} = self;
317326

318327
borrow_tracker.visit_tags(visit);
319328
data_race.visit_tags(visit);
@@ -907,8 +916,45 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
907916
}
908917

909918
#[inline(always)]
910-
fn use_addr_for_alignment_check(ecx: &MiriInterpCx<'mir, 'tcx>) -> bool {
911-
ecx.machine.check_alignment == AlignmentCheck::Int
919+
fn alignment_check(
920+
ecx: &MiriInterpCx<'mir, 'tcx>,
921+
alloc_id: AllocId,
922+
alloc_align: Align,
923+
alloc_kind: AllocKind,
924+
offset: Size,
925+
align: Align,
926+
) -> Option<Misalignment> {
927+
if ecx.machine.check_alignment != AlignmentCheck::Symbolic {
928+
// Just use the built-in check.
929+
return None;
930+
}
931+
if alloc_kind != AllocKind::LiveData {
932+
// Can't have any extra info here.
933+
return None;
934+
}
935+
// Let's see which alignment we have been promised for this allocation.
936+
let alloc_info = ecx.get_alloc_extra(alloc_id).unwrap(); // cannot fail since the allocation is live
937+
let (promised_offset, promised_align) =
938+
alloc_info.symbolic_alignment.get().unwrap_or((Size::ZERO, alloc_align));
939+
if promised_align < align {
940+
// Definitely not enough.
941+
Some(Misalignment { has: promised_align, required: align })
942+
} else {
943+
// What's the offset between us and the promised alignment?
944+
let distance = offset.bytes().wrapping_sub(promised_offset.bytes());
945+
// That must also be aligned.
946+
if distance % align.bytes() == 0 {
947+
// All looking good!
948+
None
949+
} else {
950+
// The biggest power of two through which `distance` is divisible.
951+
let distance_pow2 = 1 << distance.trailing_zeros();
952+
Some(Misalignment {
953+
has: Align::from_bytes(distance_pow2).unwrap(),
954+
required: align,
955+
})
956+
}
957+
}
912958
}
913959

914960
#[inline(always)]
@@ -1112,6 +1158,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
11121158
data_race: race_alloc,
11131159
weak_memory: buffer_alloc,
11141160
backtrace,
1161+
symbolic_alignment: Cell::new(None),
11151162
},
11161163
|ptr| ecx.global_base_pointer(ptr),
11171164
)?;

‎src/tools/miri/src/shims/foreign_items.rs

+35-2
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,7 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
464464
let ptr = this.read_pointer(ptr)?;
465465
let (alloc_id, _, _) = this.ptr_get_alloc_id(ptr).map_err(|_e| {
466466
err_machine_stop!(TerminationInfo::Abort(format!(
467-
"pointer passed to miri_get_alloc_id must not be dangling, got {ptr:?}"
467+
"pointer passed to `miri_get_alloc_id` must not be dangling, got {ptr:?}"
468468
)))
469469
})?;
470470
this.write_scalar(Scalar::from_u64(alloc_id.0.get()), dest)?;
@@ -496,7 +496,7 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
496496
let (alloc_id, offset, _) = this.ptr_get_alloc_id(ptr)?;
497497
if offset != Size::ZERO {
498498
throw_unsup_format!(
499-
"pointer passed to miri_static_root must point to beginning of an allocated block"
499+
"pointer passed to `miri_static_root` must point to beginning of an allocated block"
500500
);
501501
}
502502
this.machine.static_roots.push(alloc_id);
@@ -553,6 +553,39 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
553553
};
554554
}
555555

556+
// Promises that a pointer has a given symbolic alignment.
557+
"miri_promise_symbolic_alignment" => {
558+
let [ptr, align] = this.check_shim(abi, Abi::Rust, link_name, args)?;
559+
let ptr = this.read_pointer(ptr)?;
560+
let align = this.read_target_usize(align)?;
561+
let Ok(align) = Align::from_bytes(align) else {
562+
throw_unsup_format!(
563+
"`miri_promise_symbolic_alignment`: alignment must be a power of 2"
564+
);
565+
};
566+
let (_, addr) = ptr.into_parts(); // we know the offset is absolute
567+
if addr.bytes() % align.bytes() != 0 {
568+
throw_unsup_format!(
569+
"`miri_promise_symbolic_alignment`: pointer is not actually aligned"
570+
);
571+
}
572+
if let Ok((alloc_id, offset, ..)) = this.ptr_try_get_alloc_id(ptr) {
573+
let (_size, alloc_align, _kind) = this.get_alloc_info(alloc_id);
574+
// Not `get_alloc_extra_mut`, need to handle read-only allocations!
575+
let alloc_extra = this.get_alloc_extra(alloc_id)?;
576+
// If the newly promised alignment is bigger than the native alignment of this
577+
// allocation, and bigger than the previously promised alignment, then set it.
578+
if align > alloc_align
579+
&& !alloc_extra
580+
.symbolic_alignment
581+
.get()
582+
.is_some_and(|(_, old_align)| align <= old_align)
583+
{
584+
alloc_extra.symbolic_alignment.set(Some((offset, align)));
585+
}
586+
}
587+
}
588+
556589
// Standard C allocation
557590
"malloc" => {
558591
let [size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;

‎src/tools/miri/src/shims/mod.rs

+1-60
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ use rustc_middle::{mir, ty};
2323
use rustc_target::spec::abi::Abi;
2424

2525
use crate::*;
26-
use helpers::check_arg_count;
2726

2827
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
2928
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
@@ -39,16 +38,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
3938
let this = self.eval_context_mut();
4039
trace!("eval_fn_call: {:#?}, {:?}", instance, dest);
4140

42-
// There are some more lang items we want to hook that CTFE does not hook (yet).
43-
if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) {
44-
let args = this.copy_fn_args(args)?;
45-
let [ptr, align] = check_arg_count(&args)?;
46-
if this.align_offset(ptr, align, dest, ret, unwind)? {
47-
return Ok(None);
48-
}
49-
}
50-
51-
// Try to see if we can do something about foreign items.
41+
// For foreign items, try to see if we can emulate them.
5242
if this.tcx.is_foreign_item(instance.def_id()) {
5343
// An external function call that does not have a MIR body. We either find MIR elsewhere
5444
// or emulate its effect.
@@ -64,53 +54,4 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
6454
// Otherwise, load the MIR.
6555
Ok(Some((this.load_mir(instance.def, None)?, instance)))
6656
}
67-
68-
/// Returns `true` if the computation was performed, and `false` if we should just evaluate
69-
/// the actual MIR of `align_offset`.
70-
fn align_offset(
71-
&mut self,
72-
ptr_op: &OpTy<'tcx, Provenance>,
73-
align_op: &OpTy<'tcx, Provenance>,
74-
dest: &PlaceTy<'tcx, Provenance>,
75-
ret: Option<mir::BasicBlock>,
76-
unwind: mir::UnwindAction,
77-
) -> InterpResult<'tcx, bool> {
78-
let this = self.eval_context_mut();
79-
let ret = ret.unwrap();
80-
81-
if this.machine.check_alignment != AlignmentCheck::Symbolic {
82-
// Just use actual implementation.
83-
return Ok(false);
84-
}
85-
86-
let req_align = this.read_target_usize(align_op)?;
87-
88-
// Stop if the alignment is not a power of two.
89-
if !req_align.is_power_of_two() {
90-
this.start_panic("align_offset: align is not a power-of-two", unwind)?;
91-
return Ok(true); // nothing left to do
92-
}
93-
94-
let ptr = this.read_pointer(ptr_op)?;
95-
// If this carries no provenance, treat it like an integer.
96-
if ptr.provenance.is_none() {
97-
// Use actual implementation.
98-
return Ok(false);
99-
}
100-
101-
if let Ok((alloc_id, _offset, _)) = this.ptr_try_get_alloc_id(ptr) {
102-
// Only do anything if we can identify the allocation this goes to.
103-
let (_size, cur_align, _kind) = this.get_alloc_info(alloc_id);
104-
if cur_align.bytes() >= req_align {
105-
// If the allocation alignment is at least the required alignment we use the
106-
// real implementation.
107-
return Ok(false);
108-
}
109-
}
110-
111-
// Return error result (usize::MAX), and jump to caller.
112-
this.write_scalar(Scalar::from_target_usize(this.target_usize_max(), this), dest)?;
113-
this.go_to_block(ret);
114-
Ok(true)
115-
}
11657
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: unsupported operation: `miri_promise_symbolic_alignment`: pointer is not actually aligned
2+
--> $DIR/promise_alignment.rs:LL:CC
3+
|
4+
LL | unsafe { utils::miri_promise_symbolic_alignment(align8.add(1).cast(), 8) };
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `miri_promise_symbolic_alignment`: pointer is not actually aligned
6+
|
7+
= help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support
8+
= note: BACKTRACE:
9+
= note: inside `main` at $DIR/promise_alignment.rs:LL:CC
10+
11+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
12+
13+
error: aborting due to previous error
14+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: Undefined Behavior: accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required
2+
--> $DIR/promise_alignment.rs:LL:CC
3+
|
4+
LL | let _val = unsafe { align8.cast::<Align16>().read() };
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required
6+
|
7+
= help: this usually indicates that your program performed an invalid operation and caused Undefined Behavior
8+
= help: but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives
9+
= note: BACKTRACE:
10+
= note: inside `main` at $DIR/promise_alignment.rs:LL:CC
11+
12+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
13+
14+
error: aborting due to previous error
15+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
//@compile-flags: -Zmiri-symbolic-alignment-check
2+
//@revisions: call_unaligned_ptr read_unaligned_ptr
3+
#![feature(strict_provenance)]
4+
5+
#[path = "../../utils/mod.rs"]
6+
mod utils;
7+
8+
#[repr(align(8))]
9+
#[derive(Copy, Clone)]
10+
struct Align8(u64);
11+
12+
fn main() {
13+
let buffer = [0u32; 128]; // get some 4-aligned memory
14+
let buffer = buffer.as_ptr();
15+
// "Promising" the alignment down to 1 must not hurt.
16+
unsafe { utils::miri_promise_symbolic_alignment(buffer.cast(), 1) };
17+
let _val = unsafe { buffer.read() };
18+
19+
// Let's find a place to promise alignment 8.
20+
let align8 = if buffer.addr() % 8 == 0 {
21+
buffer
22+
} else {
23+
buffer.wrapping_add(1)
24+
};
25+
assert!(align8.addr() % 8 == 0);
26+
unsafe { utils::miri_promise_symbolic_alignment(align8.cast(), 8) };
27+
// Promising the alignment down to 1 *again* still must not hurt.
28+
unsafe { utils::miri_promise_symbolic_alignment(buffer.cast(), 1) };
29+
// Now we can do 8-aligned reads here.
30+
let _val = unsafe { align8.cast::<Align8>().read() };
31+
32+
// Make sure we error if the pointer is not actually aligned.
33+
if cfg!(call_unaligned_ptr) {
34+
unsafe { utils::miri_promise_symbolic_alignment(align8.add(1).cast(), 8) };
35+
//~[call_unaligned_ptr]^ ERROR: pointer is not actually aligned
36+
}
37+
38+
// Also don't accept even higher-aligned reads.
39+
if cfg!(read_unaligned_ptr) {
40+
#[repr(align(16))]
41+
#[derive(Copy, Clone)]
42+
struct Align16(u128);
43+
44+
let align16 = if align8.addr() % 16 == 0 {
45+
align8
46+
} else {
47+
align8.wrapping_add(2)
48+
};
49+
assert!(align16.addr() % 16 == 0);
50+
51+
let _val = unsafe { align8.cast::<Align16>().read() };
52+
//~[read_unaligned_ptr]^ ERROR: accessing memory based on pointer with alignment 8, but alignment 16 is required
53+
}
54+
}

‎src/tools/miri/tests/pass/align_offset_symbolic.rs

+8-28
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,15 @@
11
//@compile-flags: -Zmiri-symbolic-alignment-check
22
#![feature(strict_provenance)]
33

4-
use std::ptr;
5-
6-
fn test_align_offset() {
7-
let d = Box::new([0u32; 4]);
8-
// Get u8 pointer to base
9-
let raw = d.as_ptr() as *const u8;
10-
11-
assert_eq!(raw.align_offset(2), 0);
12-
assert_eq!(raw.align_offset(4), 0);
13-
assert_eq!(raw.align_offset(8), usize::MAX); // requested alignment higher than allocation alignment
14-
15-
assert_eq!(raw.wrapping_offset(1).align_offset(2), 1);
16-
assert_eq!(raw.wrapping_offset(1).align_offset(4), 3);
17-
assert_eq!(raw.wrapping_offset(1).align_offset(8), usize::MAX); // requested alignment higher than allocation alignment
18-
19-
assert_eq!(raw.wrapping_offset(2).align_offset(2), 0);
20-
assert_eq!(raw.wrapping_offset(2).align_offset(4), 2);
21-
assert_eq!(raw.wrapping_offset(2).align_offset(8), usize::MAX); // requested alignment higher than allocation alignment
22-
23-
let p = ptr::invalid::<()>(1);
24-
assert_eq!(p.align_offset(1), 0);
25-
}
26-
274
fn test_align_to() {
285
const N: usize = 4;
296
let d = Box::new([0u32; N]);
307
// Get u8 slice covering the entire thing
318
let s = unsafe { std::slice::from_raw_parts(d.as_ptr() as *const u8, 4 * N) };
329
let raw = s.as_ptr();
3310

11+
// Cases where we get the expected "middle" part without any fuzz, since the allocation is
12+
// 4-aligned.
3413
{
3514
let (l, m, r) = unsafe { s.align_to::<u32>() };
3615
assert_eq!(l.len(), 0);
@@ -63,14 +42,16 @@ fn test_align_to() {
6342
assert_eq!(raw.wrapping_offset(4), m.as_ptr() as *const u8);
6443
}
6544

45+
// Cases where we request more alignment than the allocation has.
6646
{
6747
#[repr(align(8))]
48+
#[derive(Copy, Clone)]
6849
struct Align8(u64);
6950

70-
let (l, m, r) = unsafe { s.align_to::<Align8>() }; // requested alignment higher than allocation alignment
71-
assert_eq!(l.len(), 4 * N);
72-
assert_eq!(r.len(), 0);
73-
assert_eq!(m.len(), 0);
51+
let (_l, m, _r) = unsafe { s.align_to::<Align8>() };
52+
assert!(m.len() > 0);
53+
// Ensure the symbolic alignment check has been informed that this is okay now.
54+
let _val = m[0];
7455
}
7556
}
7657

@@ -104,7 +85,6 @@ fn test_u64_array() {
10485
}
10586

10687
fn main() {
107-
test_align_offset();
10888
test_align_to();
10989
test_from_utf8();
11090
test_u64_array();

‎src/tools/miri/tests/utils/miri_extern.rs

+5
Original file line numberDiff line numberDiff line change
@@ -137,4 +137,9 @@ extern "Rust" {
137137
out: *mut std::ffi::c_char,
138138
out_size: usize,
139139
) -> usize;
140+
141+
/// Miri-provided extern function to promise that a given pointer is properly aligned for
142+
/// "symbolic" alignment checks. Will fail if the pointer is dangling or not actually aligned.
143+
/// Has no effect when alignment checks are concrete (which is the default).
144+
pub fn miri_promise_symbolic_alignment(ptr: *const (), align: usize);
140145
}

0 commit comments

Comments
 (0)
Please sign in to comment.