Skip to content

Commit 94bf0d2

Browse files
committed
review
1 parent c96804d commit 94bf0d2

File tree

12 files changed

+154
-124
lines changed

12 files changed

+154
-124
lines changed

src/shims/native_lib/mod.rs

Lines changed: 35 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,6 @@ impl AccessEvent {
5353
AccessEvent::Write(access_range, _) => access_range.clone(),
5454
}
5555
}
56-
57-
fn is_read(&self) -> bool {
58-
matches!(self, AccessEvent::Read(_))
59-
}
60-
61-
fn definitely_happened(&self) -> bool {
62-
// Anything except a maybe-write is definitive.
63-
!matches!(self, AccessEvent::Write(_, false))
64-
}
6556
}
6657

6758
/// The memory touched by a given access.
@@ -226,46 +217,56 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
226217
let this = self.eval_context_mut();
227218

228219
for evt in events.acc_events {
229-
//eprintln!("evt: {evt:?}");
230220
let evt_rg = evt.get_range();
231221
// LLVM at least permits vectorising accesses to adjacent allocations,
232222
// so we cannot assume 1 access = 1 allocation. :(
233223
let mut rg = evt_rg.addr..evt_rg.end();
234224
while let Some(curr) = rg.next() {
235-
let alloc_id = this
236-
.alloc_id_from_addr(curr.to_u64(), rg.len().try_into().unwrap(), true)
237-
.expect("Foreign code did an out-of-bounds access!");
225+
let Some(alloc_id) =
226+
this.alloc_id_from_addr(curr.to_u64(), rg.len().try_into().unwrap(), true)
227+
else {
228+
throw_ub_format!("Foreign code did an out-of-bounds access!")
229+
};
238230
let alloc = this.get_alloc_raw(alloc_id)?;
239231
let alloc_addr = alloc.get_bytes_unchecked_raw().addr();
240232

241233
// Skip forward however many bytes of the access are contained in the current allocation.
234+
// The start of the overlap range will be the greater of the alloc base address and the
235+
// lowest remaining address in the access' range; the end will be the lesser of the end
236+
// of the allocation and the end of the access' range. Both are then shifted by `alloc_addr`
237+
// so that the overlap range would have index 0 as the first byte of the allocation (which
238+
// is how the methods on the allocation expect it to be).
242239
let overlap = std::cmp::max(alloc_addr, curr).strict_sub(alloc_addr)
243240
..std::cmp::min(alloc_addr.strict_add(alloc.len()), rg.end)
244241
.strict_sub(alloc_addr);
242+
// Since `overlap` is capped in length by `rg.end`, this will inherently always be
243+
// Ok(()) so we can discard it.
245244
let _ = rg.advance_by(overlap.len());
246-
//eprintln!("overlap: {overlap:?}");
247-
248-
// Get an overlap range as an offset from the allocation base addr.
249-
//let overlap = unshifted_overlap.start..unshifted_overlap.start.strict_add(unshifted_overlap.len());
250-
251-
// Reads are infallible, writes might not be.
252-
if evt.is_read() {
253-
let p_map = alloc.provenance();
254-
for idx in overlap {
255-
// If a provenance was read by the foreign code, expose it.
256-
if let Some(prov) = p_map.get(Size::from_bytes(idx), this) {
257-
this.expose_provenance(prov)?;
245+
246+
match evt {
247+
AccessEvent::Read(_) => {
248+
let p_map = alloc.provenance();
249+
for idx in overlap {
250+
// If a provenance was read by the foreign code, expose it.
251+
if let Some(prov) = p_map.get(Size::from_bytes(idx), this) {
252+
this.expose_provenance(prov)?;
253+
}
254+
}
255+
}
256+
AccessEvent::Write(_, certain) => {
257+
// Sometimes we aren't certain if a write happened, in which case we
258+
// only initialise that data if the allocation is mutable.
259+
if certain || alloc.mutability.is_mut() {
260+
let (alloc, cx) = this.get_alloc_raw_mut(alloc_id)?;
261+
alloc.process_native_write(
262+
&cx.tcx,
263+
Some(AllocRange {
264+
start: Size::from_bytes(overlap.start),
265+
size: Size::from_bytes(overlap.len()),
266+
}),
267+
)
258268
}
259269
}
260-
} else if evt.definitely_happened() || alloc.mutability.is_mut() {
261-
let (alloc, cx) = this.get_alloc_raw_mut(alloc_id)?;
262-
alloc.process_native_write(
263-
&cx.tcx,
264-
Some(AllocRange {
265-
start: Size::from_bytes(overlap.start),
266-
size: Size::from_bytes(overlap.len()),
267-
}),
268-
)
269270
}
270271
}
271272
}

tests/native-lib/fail/trace_read.rs

Lines changed: 0 additions & 26 deletions
This file was deleted.

tests/native-lib/fail/trace_read.stderr

Lines changed: 0 additions & 40 deletions
This file was deleted.

tests/native-lib/pass/ptr_read_access.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
//@revisions: trace notrace
2-
//@[trace] only-target: linux
3-
//@[trace] only-target: gnu
4-
//@[trace] only-target: x86
5-
//@[trace] only-on-host
2+
//@[trace] only-target: x86_64-unknown-linux-gnu x86-unknown-linux-gnu
63
//@[trace] compile-flags: -Zmiri-native-lib-enable-tracing
74

85
fn main() {

tests/native-lib/pass/ptr_write_access.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
//@revisions: trace notrace
2-
//@[trace] only-target: linux
3-
//@[trace] only-target: gnu
4-
//@[trace] only-target: x86
5-
//@[trace] only-on-host
2+
//@[trace] only-target: x86_64-unknown-linux-gnu x86-unknown-linux-gnu
63
//@[trace] compile-flags: -Zmiri-native-lib-enable-tracing
74
//@compile-flags: -Zmiri-permissive-provenance
85

tests/native-lib/ptr_read_access.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,9 @@ typedef struct Static {
4949
EXPORT int32_t access_static(const Static *s_ptr) {
5050
return s_ptr->recurse->recurse->value;
5151
}
52+
53+
/* Test: unexposed_reachable_alloc */
54+
55+
EXPORT uintptr_t do_one_deref(const int32_t ***ptr) {
56+
return (uintptr_t)*ptr;
57+
}

tests/native-lib/scalar_arguments.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,3 @@ EXPORT int64_t add_short_to_long(int16_t x, int64_t y) {
3434
int32_t not_exported(void) {
3535
return 0;
3636
}
37-
38-
EXPORT void do_nothing(void) {
39-
return;
40-
}

tests/native-lib/fail/trace_write.rs renamed to tests/native-lib/tracing/fail/partial_init.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,3 @@
1-
//@only-target: linux
2-
//@only-target: gnu
3-
//@only-target: x86
4-
//@only-on-host
5-
//@compile-flags: -Zmiri-native-lib-enable-tracing
6-
71
extern "C" {
82
fn init_n(n: i32, ptr: *mut u8);
93
}
@@ -12,6 +6,8 @@ fn main() {
126
partial_init();
137
}
148

9+
// Initialise the first 2 elements of the slice from native code, and check
10+
// that the 3rd is correctly deemed uninit.
1511
fn partial_init() {
1612
let mut slice = std::mem::MaybeUninit::<[u8; 3]>::uninit();
1713
let slice_ptr = slice.as_mut_ptr().cast::<u8>();

tests/native-lib/fail/trace_write.stderr renamed to tests/native-lib/tracing/fail/partial_init.stderr

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
warning: sharing memory with a native function called via FFI
2-
--> tests/native-lib/fail/trace_write.rs:LL:CC
2+
--> tests/native-lib/tracing/fail/partial_init.rs:LL:CC
33
|
44
LL | init_n(2, slice_ptr);
55
| ^^^^^^^^^^^^^^^^^^^^ sharing memory with a native function
@@ -10,25 +10,25 @@ LL | init_n(2, slice_ptr);
1010
= help: what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free
1111
= help: tracing memory accesses in native code is not yet fully implemented, so there can be further imprecisions beyond what is documented here
1212
= note: BACKTRACE:
13-
= note: inside `partial_init` at tests/native-lib/fail/trace_write.rs:LL:CC
13+
= note: inside `partial_init` at tests/native-lib/tracing/fail/partial_init.rs:LL:CC
1414
note: inside `main`
15-
--> tests/native-lib/fail/trace_write.rs:LL:CC
15+
--> tests/native-lib/tracing/fail/partial_init.rs:LL:CC
1616
|
1717
LL | partial_init();
1818
| ^^^^^^^^^^^^^^
1919

2020
error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
21-
--> tests/native-lib/fail/trace_write.rs:LL:CC
21+
--> tests/native-lib/tracing/fail/partial_init.rs:LL:CC
2222
|
2323
LL | let _val = *slice_ptr.offset(2);
2424
| ^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
2525
|
2626
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
2727
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
2828
= note: BACKTRACE:
29-
= note: inside `partial_init` at tests/native-lib/fail/trace_write.rs:LL:CC
29+
= note: inside `partial_init` at tests/native-lib/tracing/fail/partial_init.rs:LL:CC
3030
note: inside `main`
31-
--> tests/native-lib/fail/trace_write.rs:LL:CC
31+
--> tests/native-lib/tracing/fail/partial_init.rs:LL:CC
3232
|
3333
LL | partial_init();
3434
| ^^^^^^^^^^^^^^
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
extern "C" {
2+
fn do_one_deref(ptr: *const *const *const i32) -> usize;
3+
}
4+
5+
fn main() {
6+
unexposed_reachable_alloc();
7+
}
8+
9+
// Expose 2 pointers by virtue of doing a native read and assert that the 3rd in
10+
// the chain remains properly unexposed.
11+
fn unexposed_reachable_alloc() {
12+
let inner = 42;
13+
let intermediate_a = &raw const inner;
14+
let intermediate_b = &raw const intermediate_a;
15+
let exposed = &raw const intermediate_b;
16+
// Discard the return value; it's just there so the access in C doesn't get optimised away.
17+
unsafe { do_one_deref(exposed) };
18+
// Native read should have exposed the address of intermediate_b...
19+
let valid: *const i32 = std::ptr::with_exposed_provenance(intermediate_b.addr());
20+
// but not of intermediate_a.
21+
let invalid: *const i32 = std::ptr::with_exposed_provenance(intermediate_a.addr());
22+
unsafe {
23+
let _ok = *valid;
24+
let _not_ok = *invalid; //~ ERROR: Undefined Behavior: memory access failed: attempting to access
25+
}
26+
}

0 commit comments

Comments
 (0)