Skip to content

Commit 84cfbb0

Browse files
committed
Reorganize MemoryExtra and AllocExtra structures
1 parent 2861ceb commit 84cfbb0

File tree

5 files changed

+161
-101
lines changed

5 files changed

+161
-101
lines changed

src/intptrcast.rs

Lines changed: 79 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,26 @@
1-
use std::cell::RefCell;
1+
use std::cell::{Cell, RefCell};
22

3-
use rustc::mir::interpret::AllocId;
3+
use rustc::mir::interpret::{AllocId, Pointer, InterpResult};
4+
use rustc_mir::interpret::Memory;
5+
use rustc_target::abi::Size;
46

5-
pub type MemoryState = RefCell<GlobalState>;
7+
use crate::stacked_borrows::Tag;
8+
use crate::Evaluator;
9+
10+
pub type MemoryExtra = RefCell<GlobalState>;
11+
12+
#[derive(Clone, Debug, Default)]
13+
pub struct AllocExtra {
14+
base_addr: Cell<Option<u64>>
15+
}
616

717
#[derive(Clone, Debug)]
818
pub struct GlobalState {
9-
/// This field is used as a map between the address of each allocation and its `AllocId`
19+
/// This is used as a map between the address of each allocation and its `AllocId`.
20+
/// It is always sorted
1021
pub int_to_ptr_map: Vec<(u64, AllocId)>,
22+
/// This is used as a memory address when a new pointer is casted to an integer. It
23+
/// is always larger than any address that was previously made part of a block.
1124
pub next_base_addr: u64,
1225
}
1326

@@ -20,3 +33,65 @@ impl Default for GlobalState {
2033
}
2134
}
2235
}
36+
37+
impl<'mir, 'tcx> GlobalState {
38+
pub fn int_to_ptr(
39+
base_addr: u64,
40+
memory: &Memory<'mir, 'tcx, Evaluator<'tcx>>,
41+
) -> InterpResult<'tcx, Pointer<Tag>> {
42+
let global_state = memory.extra.intptrcast.borrow();
43+
44+
match global_state.int_to_ptr_map.binary_search_by_key(&base_addr, |(addr, _)| *addr) {
45+
Ok(pos) => {
46+
let (_, alloc_id) = global_state.int_to_ptr_map[pos];
47+
// `base_addr` is the starting address for an allocation, the offset should be
48+
// zero. The pointer is untagged because it was created from a cast
49+
Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(0), Tag::Untagged))
50+
},
51+
Err(0) => err!(DanglingPointerDeref),
52+
Err(pos) => {
53+
// This is the gargest of the adresses smaller than `base_addr`,
54+
// i.e. the greatest lower bound (glb)
55+
let (glb, alloc_id) = global_state.int_to_ptr_map[pos - 1];
56+
// This never overflows because `base_addr >= glb`
57+
let offset = base_addr - glb;
58+
// If the offset exceeds the size of the allocation, this access is illegal
59+
if offset <= memory.get(alloc_id)?.bytes.len() as u64 {
60+
// This pointer is untagged because it was created from a cast
61+
Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(offset), Tag::Untagged))
62+
} else {
63+
err!(DanglingPointerDeref)
64+
}
65+
}
66+
}
67+
}
68+
69+
pub fn ptr_to_int(
70+
ptr: Pointer<Tag>,
71+
memory: &Memory<'mir, 'tcx, Evaluator<'tcx>>,
72+
) -> InterpResult<'tcx, u64> {
73+
let mut global_state = memory.extra.intptrcast.borrow_mut();
74+
75+
let alloc = memory.get(ptr.alloc_id)?;
76+
77+
let base_addr = match alloc.extra.intptrcast.base_addr.get() {
78+
Some(base_addr) => base_addr,
79+
None => {
80+
let base_addr = global_state.next_base_addr;
81+
global_state.next_base_addr += alloc.bytes.len() as u64;
82+
83+
alloc.extra.intptrcast.base_addr.set(Some(base_addr));
84+
85+
let elem = (base_addr, ptr.alloc_id);
86+
87+
// Given that `next_base_addr` increases in each allocation, pushing the
88+
// corresponding tuple keeps `int_to_ptr_map` sorted
89+
global_state.int_to_ptr_map.push(elem);
90+
91+
base_addr
92+
}
93+
};
94+
95+
Ok(base_addr + ptr.offset.bytes())
96+
}
97+
}

src/lib.rs

Lines changed: 17 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ mod memory;
2525

2626
use std::collections::HashMap;
2727
use std::borrow::Cow;
28-
use std::cell::Cell;
2928
use std::rc::Rc;
3029

3130
use rand::rngs::StdRng;
@@ -387,7 +386,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> {
387386
type MemoryKinds = MiriMemoryKind;
388387

389388
type FrameExtra = stacked_borrows::CallId;
390-
type MemoryExtra = memory::MemoryState;
389+
type MemoryExtra = memory::MemoryExtra;
391390
type AllocExtra = memory::AllocExtra;
392391
type PointerTag = Tag;
393392

@@ -513,17 +512,17 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> {
513512
) -> (Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>>, Self::PointerTag) {
514513
let kind = kind.expect("we set our STATIC_KIND so this cannot be None");
515514
let alloc = alloc.into_owned();
516-
let (extra, base_tag) = Stacks::new_allocation(
515+
let (stacks, base_tag) = Stacks::new_allocation(
517516
id,
518517
Size::from_bytes(alloc.bytes.len() as u64),
519-
Rc::clone(&memory.extra.stacked),
518+
Rc::clone(&memory.extra.stacked_borrows),
520519
kind,
521520
);
522521
if kind != MiriMemoryKind::Static.into() {
523522
assert!(alloc.relocations.is_empty(), "Only statics can come initialized with inner pointers");
524523
// Now we can rely on the inner pointers being static, too.
525524
}
526-
let mut memory_extra = memory.extra.stacked.borrow_mut();
525+
let mut memory_extra = memory.extra.stacked_borrows.borrow_mut();
527526
let alloc: Allocation<Tag, Self::AllocExtra> = Allocation {
528527
bytes: alloc.bytes,
529528
relocations: Relocations::from_presorted(
@@ -537,8 +536,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> {
537536
align: alloc.align,
538537
mutability: alloc.mutability,
539538
extra: AllocExtra {
540-
stacks: extra,
541-
base_addr: Cell::new(None),
539+
stacked_borrows: stacks,
540+
intptrcast: Default::default(),
542541
},
543542
};
544543
(Cow::Owned(alloc), base_tag)
@@ -549,7 +548,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> {
549548
id: AllocId,
550549
memory: &Memory<'mir, 'tcx, Self>,
551550
) -> Self::PointerTag {
552-
memory.extra.stacked.borrow_mut().static_base_ptr(id)
551+
memory.extra.stacked_borrows.borrow_mut().static_base_ptr(id)
553552
}
554553

555554
#[inline(always)]
@@ -574,49 +573,27 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> {
574573
fn stack_push(
575574
ecx: &mut InterpretCx<'mir, 'tcx, Self>,
576575
) -> InterpResult<'tcx, stacked_borrows::CallId> {
577-
Ok(ecx.memory().extra.stacked.borrow_mut().new_call())
576+
Ok(ecx.memory().extra.stacked_borrows.borrow_mut().new_call())
578577
}
579578

580579
#[inline(always)]
581580
fn stack_pop(
582581
ecx: &mut InterpretCx<'mir, 'tcx, Self>,
583582
extra: stacked_borrows::CallId,
584583
) -> InterpResult<'tcx> {
585-
Ok(ecx.memory().extra.stacked.borrow_mut().end_call(extra))
584+
Ok(ecx.memory().extra.stacked_borrows.borrow_mut().end_call(extra))
586585
}
587586

588587
fn int_to_ptr(
589588
int: u64,
590589
memory: &Memory<'mir, 'tcx, Self>,
591590
) -> InterpResult<'tcx, Pointer<Self::PointerTag>> {
592591
if int == 0 {
593-
return err!(InvalidNullPointerUsage);
594-
}
595-
596-
if memory.extra.rng.is_none() {
597-
return err!(ReadBytesAsPointer);
598-
}
599-
600-
let extra = memory.extra.intptrcast.borrow();
601-
602-
match extra.int_to_ptr_map.binary_search_by_key(&int, |(int, _)| *int) {
603-
Ok(pos) => {
604-
let (_, alloc_id) = extra.int_to_ptr_map[pos];
605-
Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(0), Tag::Untagged))
606-
}
607-
Err(pos) => {
608-
if pos > 0 {
609-
let (glb, alloc_id) = extra.int_to_ptr_map[pos - 1];
610-
let offset = int - glb;
611-
if offset <= memory.get(alloc_id)?.bytes.len() as u64 {
612-
Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(offset), Tag::Untagged))
613-
} else {
614-
return err!(DanglingPointerDeref);
615-
}
616-
} else {
617-
return err!(DanglingPointerDeref);
618-
}
619-
}
592+
err!(InvalidNullPointerUsage)
593+
} else if memory.extra.rng.is_none() {
594+
err!(ReadBytesAsPointer)
595+
} else {
596+
intptrcast::GlobalState::int_to_ptr(int, memory)
620597
}
621598
}
622599

@@ -625,31 +602,9 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> {
625602
memory: &Memory<'mir, 'tcx, Self>,
626603
) -> InterpResult<'tcx, u64> {
627604
if memory.extra.rng.is_none() {
628-
return err!(ReadPointerAsBytes);
605+
err!(ReadPointerAsBytes)
606+
} else {
607+
intptrcast::GlobalState::ptr_to_int(ptr, memory)
629608
}
630-
631-
let mut extra = memory.extra.intptrcast.borrow_mut();
632-
633-
let alloc = memory.get(ptr.alloc_id)?;
634-
635-
let base_addr = match alloc.extra.base_addr.get() {
636-
Some(base_addr) => base_addr,
637-
None => {
638-
let base_addr = extra.next_base_addr;
639-
extra.next_base_addr += alloc.bytes.len() as u64;
640-
641-
alloc.extra.base_addr.set(Some(base_addr));
642-
643-
let elem = (base_addr, ptr.alloc_id);
644-
645-
// Given that `next_base_addr` increases in each allocation, pushing the
646-
// corresponding tuple keeps `int_to_ptr_map` sorted
647-
extra.int_to_ptr_map.push(elem);
648-
649-
base_addr
650-
}
651-
};
652-
653-
Ok(base_addr + ptr.offset.bytes())
654609
}
655610
}

src/memory.rs

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,24 @@
1-
use std::cell::Cell;
21
use rand::rngs::StdRng;
32

43
use rustc_mir::interpret::{Pointer, Allocation, AllocationExtra, InterpResult};
54
use rustc_target::abi::Size;
65

76
use crate::{stacked_borrows, intptrcast};
8-
use crate::stacked_borrows::{Tag, AccessKind};
7+
use crate::stacked_borrows::Tag;
98

109
#[derive(Default, Clone, Debug)]
11-
pub struct MemoryState {
12-
pub stacked: stacked_borrows::MemoryState,
13-
pub intptrcast: intptrcast::MemoryState,
14-
/// The random number generator to use if Miri
15-
/// is running in non-deterministic mode
10+
pub struct MemoryExtra {
11+
pub stacked_borrows: stacked_borrows::MemoryExtra,
12+
pub intptrcast: intptrcast::MemoryExtra,
13+
/// The random number generator to use if Miri is running in non-deterministic mode and to
14+
/// enable intptrcast
1615
pub(crate) rng: Option<StdRng>
1716
}
1817

19-
#[derive(Debug, Clone,)]
18+
#[derive(Debug, Clone)]
2019
pub struct AllocExtra {
21-
pub stacks: stacked_borrows::Stacks,
22-
pub base_addr: Cell<Option<u64>>,
20+
pub stacked_borrows: stacked_borrows::AllocExtra,
21+
pub intptrcast: intptrcast::AllocExtra,
2322
}
2423

2524
impl AllocationExtra<Tag> for AllocExtra {
@@ -29,11 +28,7 @@ impl AllocationExtra<Tag> for AllocExtra {
2928
ptr: Pointer<Tag>,
3029
size: Size,
3130
) -> InterpResult<'tcx> {
32-
trace!("read access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes());
33-
alloc.extra.stacks.for_each(ptr, size, |stack, global| {
34-
stack.access(AccessKind::Read, ptr.tag, global)?;
35-
Ok(())
36-
})
31+
alloc.extra.stacked_borrows.memory_read(ptr, size)
3732
}
3833

3934
#[inline(always)]
@@ -42,11 +37,7 @@ impl AllocationExtra<Tag> for AllocExtra {
4237
ptr: Pointer<Tag>,
4338
size: Size,
4439
) -> InterpResult<'tcx> {
45-
trace!("write access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes());
46-
alloc.extra.stacks.for_each(ptr, size, |stack, global| {
47-
stack.access(AccessKind::Write, ptr.tag, global)?;
48-
Ok(())
49-
})
40+
alloc.extra.stacked_borrows.memory_written(ptr, size)
5041
}
5142

5243
#[inline(always)]
@@ -55,9 +46,6 @@ impl AllocationExtra<Tag> for AllocExtra {
5546
ptr: Pointer<Tag>,
5647
size: Size,
5748
) -> InterpResult<'tcx> {
58-
trace!("deallocation with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes());
59-
alloc.extra.stacks.for_each(ptr, size, |stack, global| {
60-
stack.dealloc(ptr.tag, global)
61-
})
49+
alloc.extra.stacked_borrows.memory_deallocated(ptr, size)
6250
}
6351
}

src/operator.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> {
4444

4545
trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right);
4646

47+
// If intptrcast is enabled and the operation is not an offset
48+
// we can force the cast from pointers to integer addresses and
49+
// then dispatch to rustc binary operation method
4750
if self.memory().extra.rng.is_some() && bin_op != Offset {
4851
let l_bits = self.force_bits(left.imm.to_scalar()?, left.layout.size)?;
4952
let r_bits = self.force_bits(right.imm.to_scalar()?, right.layout.size)?;

0 commit comments

Comments
 (0)