Skip to content

Commit cf6330c

Browse files
committed
start implementing MiriAllocBytes
attempt changing Bytes in MiriMachine to MiriAllocBytes rename miri_alloc_bytes to alloc_bytes generalize impl VisitProvenance for Allocation for any Bytes: AllocBytes mend MiriAllocBytes -> Self::Bytes fix Invariant documentation and bugs (drop), impl Clone Update MiriAllocBytes description Co-authored-by: Ralf Jung <[email protected]> Rephrase MiriAllocBytes ptr invariant Co-authored-by: Ralf Jung <[email protected]> Update MiriAllocBytes ptr documentation Co-authored-by: Ralf Jung <[email protected]> fix safety comment in MiriAllocBytes::clone fix safety comment in MiriAllocBytes::from_bytes try implementing clone without unsafe remove derive(PartialEq,Eq,Hash), fix fmt move ptr.is_null() check inside only necessary branch use std::ptr::without_provenance_mut, requiring feature(strict_provenance) align.bytes_usize() instead of align.bytes().try_into().unwrap() Update src/provenance_gc.rs Co-authored-by: Ralf Jung <[email protected]> fix clippy error on deref
1 parent 35cbdf8 commit cf6330c

File tree

5 files changed

+119
-6
lines changed

5 files changed

+119
-6
lines changed

src/alloc_bytes.rs

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
use std::alloc;
2+
use std::alloc::Layout;
3+
use std::borrow::Cow;
4+
use std::slice;
5+
6+
use rustc_middle::mir::interpret::AllocBytes;
7+
use rustc_target::abi::{Align, Size};
8+
9+
/// Allocation bytes that explicitly handle the layout of the data they're storing.
10+
/// This is necessary to interface with native code that accesses the program store in Miri.
11+
#[derive(Debug)]
12+
pub struct MiriAllocBytes {
13+
/// Stored layout information about the allocation.
14+
layout: alloc::Layout,
15+
/// Pointer to the allocation contents.
16+
/// Invariant:
17+
/// * If `self.layout.size() == 0`, then `self.ptr` is some suitably aligned pointer
18+
/// without provenance (and no actual memory was allocated).
19+
/// * Otherwise, `self.ptr` points to memory allocated with `self.layout`.
20+
ptr: *mut u8,
21+
}
22+
23+
impl Clone for MiriAllocBytes {
24+
fn clone(&self) -> Self {
25+
let bytes: Cow<'_, [u8]> = Cow::Borrowed(self);
26+
let align = Align::from_bytes(self.layout.align().try_into().unwrap()).unwrap();
27+
MiriAllocBytes::from_bytes(bytes, align)
28+
}
29+
}
30+
31+
impl Drop for MiriAllocBytes {
32+
fn drop(&mut self) {
33+
if self.layout.size() != 0 {
34+
// SAFETY: Invariant, `self.ptr` points to memory allocated with `self.layout`.
35+
unsafe { alloc::dealloc(self.ptr, self.layout) }
36+
}
37+
}
38+
}
39+
40+
impl std::ops::Deref for MiriAllocBytes {
41+
type Target = [u8];
42+
43+
fn deref(&self) -> &Self::Target {
44+
// SAFETY: `ptr` is non-null, properly aligned, and valid for reading out `self.layout.size()`-many bytes.
45+
// Note that due to the invariant this is true even if `self.layout.size() == 0`.
46+
unsafe { slice::from_raw_parts(self.ptr, self.layout.size()) }
47+
}
48+
}
49+
50+
impl std::ops::DerefMut for MiriAllocBytes {
51+
fn deref_mut(&mut self) -> &mut Self::Target {
52+
// SAFETY: `ptr` is non-null, properly aligned, and valid for reading out `self.layout.size()`-many bytes.
53+
// Note that due to the invariant this is true even if `self.layout.size() == 0`.
54+
unsafe { slice::from_raw_parts_mut(self.ptr, self.layout.size()) }
55+
}
56+
}
57+
58+
impl MiriAllocBytes {
59+
/// This method factors out how a `MiriAllocBytes` object is allocated,
60+
/// specifically given an allocation function `alloc_fn`.
61+
/// `alloc_fn` is only used if `size != 0`.
62+
/// Returns `Err(layout)` if the allocation function returns a `ptr` that is `ptr.is_null()`.
63+
fn alloc_with(
64+
size: usize,
65+
align: usize,
66+
alloc_fn: impl FnOnce(Layout) -> *mut u8,
67+
) -> Result<MiriAllocBytes, Layout> {
68+
let layout = Layout::from_size_align(size, align).unwrap();
69+
let ptr = if size == 0 {
70+
std::ptr::without_provenance_mut(align)
71+
} else {
72+
let ptr = alloc_fn(layout);
73+
if ptr.is_null() {
74+
return Err(layout);
75+
}
76+
ptr
77+
};
78+
// SAFETY: All `MiriAllocBytes` invariants are fulfilled.
79+
Ok(Self { ptr, layout })
80+
}
81+
}
82+
83+
impl AllocBytes for MiriAllocBytes {
84+
fn from_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>, align: Align) -> Self {
85+
let slice = slice.into();
86+
let size = slice.len();
87+
let align = align.bytes_usize();
88+
// SAFETY: `alloc_fn` will only be used if `size != 0`.
89+
let alloc_fn = |layout| unsafe { alloc::alloc(layout) };
90+
let alloc_bytes = MiriAllocBytes::alloc_with(size, align, alloc_fn)
91+
.unwrap_or_else(|layout| alloc::handle_alloc_error(layout));
92+
// SAFETY: `alloc_bytes.ptr` and `slice.as_ptr()` are non-null, properly aligned
93+
// and valid for the `size`-many bytes to be copied.
94+
unsafe { alloc_bytes.ptr.copy_from(slice.as_ptr(), size) };
95+
alloc_bytes
96+
}
97+
98+
fn zeroed(size: Size, align: Align) -> Option<Self> {
99+
let size = size.bytes_usize();
100+
let align = align.bytes_usize();
101+
// SAFETY: `alloc_fn` will only be used if `size != 0`.
102+
let alloc_fn = |layout| unsafe { alloc::alloc_zeroed(layout) };
103+
MiriAllocBytes::alloc_with(size, align, alloc_fn).ok()
104+
}
105+
106+
fn as_mut_ptr(&mut self) -> *mut u8 {
107+
self.ptr
108+
}
109+
}

src/diagnostics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,7 @@ pub fn report_error<'tcx, 'mir>(
459459

460460
pub fn report_leaks<'mir, 'tcx>(
461461
ecx: &InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>,
462-
leaks: Vec<(AllocId, MemoryKind, Allocation<Provenance, AllocExtra<'tcx>>)>,
462+
leaks: Vec<(AllocId, MemoryKind, Allocation<Provenance, AllocExtra<'tcx>, MiriAllocBytes>)>,
463463
) {
464464
let mut any_pruned = false;
465465
for (id, kind, mut alloc) in leaks {

src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#![feature(lint_reasons)]
1414
#![feature(trait_upcasting)]
1515
#![feature(strict_overflow_ops)]
16+
#![feature(strict_provenance)]
1617
// Configure clippy and other lints
1718
#![allow(
1819
clippy::collapsible_else_if,
@@ -74,6 +75,7 @@ extern crate rustc_target;
7475
extern crate rustc_driver;
7576

7677
mod alloc_addresses;
78+
mod alloc_bytes;
7779
mod borrow_tracker;
7880
mod clock;
7981
mod concurrency;
@@ -107,6 +109,7 @@ pub use crate::shims::tls::TlsData;
107109
pub use crate::shims::EmulateItemResult;
108110

109111
pub use crate::alloc_addresses::{EvalContextExt as _, ProvenanceMode};
112+
pub use crate::alloc_bytes::MiriAllocBytes;
110113
pub use crate::borrow_tracker::stacked_borrows::{
111114
EvalContextExt as _, Item, Permission, Stack, Stacks,
112115
};

src/machine.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -862,7 +862,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
862862

863863
type Provenance = Provenance;
864864
type ProvenanceExtra = ProvenanceExtra;
865-
type Bytes = Box<[u8]>;
865+
type Bytes = MiriAllocBytes;
866866

867867
type MemoryMap =
868868
MonoHashMap<AllocId, (MemoryKind, Allocation<Provenance, Self::AllocExtra, Self::Bytes>)>;
@@ -1088,8 +1088,9 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
10881088
id: AllocId,
10891089
alloc: Cow<'b, Allocation>,
10901090
kind: Option<MemoryKind>,
1091-
) -> InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance, Self::AllocExtra>>> {
1092-
let kind = kind.expect("we set our GLOBAL_KIND so this cannot be None");
1091+
) -> InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance, Self::AllocExtra, Self::Bytes>>>
1092+
{
1093+
let kind = kind.expect("we set our STATIC_KIND so this cannot be None");
10931094
if ecx.machine.tracked_alloc_ids.contains(&id) {
10941095
ecx.emit_diagnostic(NonHaltingDiagnostic::CreatedAlloc(
10951096
id,
@@ -1126,7 +1127,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
11261127
Some(ecx.generate_stacktrace())
11271128
};
11281129

1129-
let alloc: Allocation<Provenance, Self::AllocExtra> = alloc.adjust_from_tcx(
1130+
let alloc: Allocation<Provenance, Self::AllocExtra, Self::Bytes> = alloc.adjust_from_tcx(
11301131
&ecx.tcx,
11311132
AllocExtra {
11321133
borrow_tracker,

src/provenance_gc.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ impl VisitProvenance for OpTy<'_, Provenance> {
122122
}
123123
}
124124

125-
impl VisitProvenance for Allocation<Provenance, AllocExtra<'_>> {
125+
impl VisitProvenance for Allocation<Provenance, AllocExtra<'_>, MiriAllocBytes> {
126126
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
127127
for prov in self.provenance().provenances() {
128128
prov.visit_provenance(visit);

0 commit comments

Comments
 (0)