Skip to content

Commit 1522a47

Browse files
committed
Auto merge of #795 - RalfJung:intptrcast, r=RalfJung
tweak inttoptr allocation behavior - Make `align_addr` not offset by `align` for no reason. - Add some random slack between allocations to give them the chance to not be aligned. Cc @christianpoveda Fixes rust-lang/miri#791
2 parents 9e42475 + 0bb50ad commit 1522a47

File tree

5 files changed

+55
-9
lines changed

5 files changed

+55
-9
lines changed

src/eval.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use rustc::mir;
1010
use crate::{
1111
InterpResult, InterpError, InterpretCx, StackPopCleanup, struct_error,
1212
Scalar, Tag, Pointer,
13-
MiriMemoryKind, Evaluator, TlsEvalContextExt,
13+
MemoryExtra, MiriMemoryKind, Evaluator, TlsEvalContextExt,
1414
};
1515

1616
/// Configuration needed to spawn a Miri instance.
@@ -36,7 +36,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
3636
);
3737

3838
// FIXME: InterpretCx::new should take an initial MemoryExtra
39-
ecx.memory_mut().extra.rng = config.seed.map(StdRng::seed_from_u64);
39+
ecx.memory_mut().extra = MemoryExtra::with_rng(config.seed.map(StdRng::seed_from_u64));
4040

4141
let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id);
4242
let main_mir = ecx.load_mir(main_instance.def)?;

src/fn_call.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -982,6 +982,7 @@ fn gen_random<'mir, 'tcx>(
982982

983983
let data = match &mut this.memory_mut().extra.rng {
984984
Some(rng) => {
985+
let mut rng = rng.borrow_mut();
985986
let mut data = vec![0; len];
986987
rng.fill_bytes(&mut data);
987988
data

src/intptrcast.rs

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use std::cell::{Cell, RefCell};
22

3+
use rand::Rng;
4+
35
use rustc::mir::interpret::{AllocId, Pointer, InterpResult};
46
use rustc_mir::interpret::Memory;
57
use rustc_target::abi::Size;
@@ -73,14 +75,24 @@ impl<'mir, 'tcx> GlobalState {
7375
let mut global_state = memory.extra.intptrcast.borrow_mut();
7476

7577
let alloc = memory.get(ptr.alloc_id)?;
78+
let align = alloc.align.bytes();
7679

7780
let base_addr = match alloc.extra.intptrcast.base_addr.get() {
7881
Some(base_addr) => base_addr,
7982
None => {
8083
// This allocation does not have a base address yet, pick one.
81-
let base_addr = Self::align_addr(global_state.next_base_addr, alloc.align.bytes());
82-
global_state.next_base_addr = base_addr + alloc.bytes.len() as u64;
84+
// Leave some space to the previous allocation, to give it some chance to be less aligned.
85+
let slack = {
86+
let mut rng = memory.extra.rng.as_ref().unwrap().borrow_mut();
87+
// This means that `(global_state.next_base_addr + slack) % 16` is uniformly distributed.
88+
rng.gen_range(0, 16)
89+
};
90+
// From next_base_addr + slack, round up to adjust for alignment.
91+
let base_addr = Self::align_addr(global_state.next_base_addr + slack, align);
8392
alloc.extra.intptrcast.base_addr.set(Some(base_addr));
93+
94+
// Remember next base address.
95+
global_state.next_base_addr = base_addr + alloc.bytes.len() as u64;
8496
// Given that `next_base_addr` increases in each allocation, pushing the
8597
// corresponding tuple keeps `int_to_ptr_map` sorted
8698
global_state.int_to_ptr_map.push((base_addr, ptr.alloc_id));
@@ -89,13 +101,27 @@ impl<'mir, 'tcx> GlobalState {
89101
}
90102
};
91103

92-
debug_assert_eq!(base_addr % alloc.align.bytes(), 0); // sanity check
104+
debug_assert_eq!(base_addr % align, 0); // sanity check
93105
Ok(base_addr + ptr.offset.bytes())
94106
}
95107

96108
/// Shifts `addr` to make it aligned with `align` by rounding `addr` to the smallest multiple
97-
/// of `align` that is strictly larger to `addr`
109+
/// of `align` that is larger or equal to `addr`
98110
fn align_addr(addr: u64, align: u64) -> u64 {
99-
addr + align - addr % align
111+
match addr % align {
112+
0 => addr,
113+
rem => addr + align - rem
114+
}
115+
}
116+
}
117+
118+
#[cfg(test)]
119+
mod tests {
120+
use super::*;
121+
122+
#[test]
123+
fn test_align_addr() {
124+
assert_eq!(GlobalState::align_addr(37, 4), 40);
125+
assert_eq!(GlobalState::align_addr(44, 4), 44);
100126
}
101127
}

src/machine.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::rc::Rc;
22
use std::borrow::Cow;
33
use std::collections::HashMap;
4+
use std::cell::RefCell;
45

56
use rand::rngs::StdRng;
67

@@ -46,15 +47,15 @@ pub struct MemoryExtra {
4647
pub intptrcast: intptrcast::MemoryExtra,
4748
/// The random number generator to use if Miri is running in non-deterministic mode and to
4849
/// enable intptrcast
49-
pub(crate) rng: Option<StdRng>
50+
pub(crate) rng: Option<RefCell<StdRng>>
5051
}
5152

5253
impl MemoryExtra {
5354
pub fn with_rng(rng: Option<StdRng>) -> Self {
5455
MemoryExtra {
5556
stacked_borrows: Default::default(),
5657
intptrcast: Default::default(),
57-
rng,
58+
rng: rng.map(RefCell::new),
5859
}
5960
}
6061
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Validation makes this fail in the wrong place
2+
// compile-flags: -Zmiri-disable-validation -Zmiri-seed=0000000000000000
3+
4+
// Even with intptrcast and without validation, we want to be *sure* to catch bugs
5+
// that arise from pointers being insufficiently aligned. The only way to achieve
6+
// that is not not let programs exploit integer information for alignment, so here
7+
// we test that this is indeed the case.
8+
fn main() {
9+
let x = &mut [0u8; 3];
10+
let base_addr = x as *mut _ as usize;
11+
let u16_ref = unsafe { if base_addr % 2 == 0 {
12+
&mut *(base_addr as *mut u16)
13+
} else {
14+
&mut *((base_addr+1) as *mut u16)
15+
} };
16+
*u16_ref = 2; //~ ERROR tried to access memory with alignment 1, but alignment 2 is required
17+
println!("{:?}", x);
18+
}

0 commit comments

Comments
 (0)