Skip to content

Commit 2a761de

Browse files
committed
Auto merge of #3207 - rust-lang:rustup-2023-12-04, r=RalfJung
Automatic Rustup
2 parents 8c93185 + 7a32b56 commit 2a761de

18 files changed

+200
-104
lines changed

cargo-miri/src/phases.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,14 @@ pub fn phase_runner(mut binary_args: impl Iterator<Item = String>, phase: Runner
501501
// Set missing env vars. We prefer build-time env vars over run-time ones; see
502502
// <https://github.com/rust-lang/miri/issues/1661> for the kind of issue that fixes.
503503
for (name, val) in info.env {
504+
// `CARGO_MAKEFLAGS` contains information about how to reach the
505+
// jobserver, but by the time the program is being run, that jobserver
506+
// no longer exists. Hence we shouldn't forward this.
507+
// FIXME: Miri builds the final crate without a jobserver.
508+
// This may be fixed with github.com/rust-lang/cargo/issues/12597.
509+
if name == "CARGO_MAKEFLAGS" {
510+
continue;
511+
}
504512
if let Some(old_val) = env::var_os(&name) {
505513
if old_val == val {
506514
// This one did not actually change, no need to re-set it.

rust-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
225e36cff9809948d6567ab16f75d7b087ea83a7
1+
c9808f87028e16d134438787cab3d4cc16d05fe2

src/machine.rs

Lines changed: 51 additions & 4 deletions
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 VisitProvenance for AllocExtra<'_> {
315318
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
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_provenance(visit);
319328
data_race.visit_provenance(visit);
@@ -902,8 +911,45 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
902911
}
903912

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

909955
#[inline(always)]
@@ -1107,6 +1153,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
11071153
data_race: race_alloc,
11081154
weak_memory: buffer_alloc,
11091155
backtrace,
1156+
symbolic_alignment: Cell::new(None),
11101157
},
11111158
|ptr| ecx.global_base_pointer(ptr),
11121159
)?;

src/shims/foreign_items.rs

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,7 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
467467
let ptr = this.read_pointer(ptr)?;
468468
let (alloc_id, _, _) = this.ptr_get_alloc_id(ptr).map_err(|_e| {
469469
err_machine_stop!(TerminationInfo::Abort(format!(
470-
"pointer passed to miri_get_alloc_id must not be dangling, got {ptr:?}"
470+
"pointer passed to `miri_get_alloc_id` must not be dangling, got {ptr:?}"
471471
)))
472472
})?;
473473
this.write_scalar(Scalar::from_u64(alloc_id.0.get()), dest)?;
@@ -499,7 +499,7 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
499499
let (alloc_id, offset, _) = this.ptr_get_alloc_id(ptr)?;
500500
if offset != Size::ZERO {
501501
throw_unsup_format!(
502-
"pointer passed to miri_static_root must point to beginning of an allocated block"
502+
"pointer passed to `miri_static_root` must point to beginning of an allocated block"
503503
);
504504
}
505505
this.machine.static_roots.push(alloc_id);
@@ -556,6 +556,40 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
556556
};
557557
}
558558

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

src/shims/mod.rs

Lines changed: 1 addition & 60 deletions
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
}

tests/fail/provenance/ptr_int_unexposed.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//@compile-flags: -Zmiri-permissive-provenance
2-
#![feature(strict_provenance)]
2+
#![feature(strict_provenance, exposed_provenance)]
33

44
fn main() {
55
let x: i32 = 3;

tests/fail/provenance/ptr_invalid.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#![feature(strict_provenance)]
1+
#![feature(strict_provenance, exposed_provenance)]
22

33
// Ensure that a `ptr::invalid` ptr is truly invalid.
44
fn main() {

tests/fail/provenance/strict_provenance_cast.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//@compile-flags: -Zmiri-strict-provenance
2-
#![feature(strict_provenance)]
2+
#![feature(exposed_provenance)]
33

44
fn main() {
55
let addr = &0 as *const i32 as usize;

tests/fail/stacked_borrows/exposed_only_ro.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//@compile-flags: -Zmiri-permissive-provenance
2-
#![feature(strict_provenance)]
2+
#![feature(exposed_provenance)]
33

44
// If we have only exposed read-only pointers, doing a write through a wildcard ptr should fail.
55

Lines changed: 14 additions & 0 deletions
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 1 previous error
14+
Lines changed: 15 additions & 0 deletions
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 1 previous error
15+
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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 { buffer } else { buffer.wrapping_add(1) };
21+
assert!(align8.addr() % 8 == 0);
22+
unsafe { utils::miri_promise_symbolic_alignment(align8.cast(), 8) };
23+
// Promising the alignment down to 1 *again* still must not hurt.
24+
unsafe { utils::miri_promise_symbolic_alignment(buffer.cast(), 1) };
25+
// Now we can do 8-aligned reads here.
26+
let _val = unsafe { align8.cast::<Align8>().read() };
27+
28+
// Make sure we error if the pointer is not actually aligned.
29+
if cfg!(call_unaligned_ptr) {
30+
unsafe { utils::miri_promise_symbolic_alignment(align8.add(1).cast(), 8) };
31+
//~[call_unaligned_ptr]^ ERROR: pointer is not actually aligned
32+
}
33+
34+
// Also don't accept even higher-aligned reads.
35+
if cfg!(read_unaligned_ptr) {
36+
#[repr(align(16))]
37+
#[derive(Copy, Clone)]
38+
struct Align16(u128);
39+
40+
let align16 = if align8.addr() % 16 == 0 { align8 } else { align8.wrapping_add(2) };
41+
assert!(align16.addr() % 16 == 0);
42+
43+
let _val = unsafe { align8.cast::<Align16>().read() };
44+
//~[read_unaligned_ptr]^ ERROR: accessing memory based on pointer with alignment 8, but alignment 16 is required
45+
}
46+
}

0 commit comments

Comments
 (0)