Skip to content

Commit 7d6685d

Browse files
committed
more review stuff
1 parent 93015d6 commit 7d6685d

File tree

7 files changed

+53
-45
lines changed

7 files changed

+53
-45
lines changed

src/alloc/isolated_alloc.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -303,14 +303,12 @@ impl IsolatedAlloc {
303303
}
304304

305305
/// Returns a vector of page addresses managed by the allocator.
306-
pub fn pages(&self) -> Vec<usize> {
306+
pub fn pages(&self) -> impl Iterator<Item = usize> {
307307
let pages = self.page_ptrs.iter().map(|p| p.expose_provenance().get());
308-
let pages = pages.chain(self.huge_ptrs.iter().flat_map(|(ptr, size)| {
308+
pages.chain(self.huge_ptrs.iter().flat_map(|(ptr, size)| {
309309
(0..size / self.page_size)
310310
.map(|i| ptr.expose_provenance().get().strict_add(i * self.page_size))
311-
}));
312-
313-
pages.collect()
311+
}))
314312
}
315313

316314
/// Protects all owned memory as `PROT_NONE`, preventing accesses.

src/bin/miri.rs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,10 @@ fn run_compiler_and_exit(
354354
args: &[String],
355355
callbacks: &mut (dyn rustc_driver::Callbacks + Send),
356356
) -> ! {
357+
// Install the ctrlc handler that sets `rustc_const_eval::CTRL_C_RECEIVED`, even if
358+
// MIRI_BE_RUSTC is set.
359+
rustc_driver::install_ctrlc_handler();
360+
357361
// Invoke compiler, catch any unwinding panics and handle return code.
358362
let exit_code =
359363
rustc_driver::catch_with_exit_code(move || rustc_driver::run_compiler(args, callbacks));
@@ -438,10 +442,6 @@ fn main() {
438442
let args = rustc_driver::catch_fatal_errors(|| rustc_driver::args::raw_args(&early_dcx))
439443
.unwrap_or_else(|_| std::process::exit(rustc_driver::EXIT_FAILURE));
440444

441-
// Install the ctrlc handler that sets `rustc_const_eval::CTRL_C_RECEIVED`, even if
442-
// MIRI_BE_RUSTC is set.
443-
rustc_driver::install_ctrlc_handler();
444-
445445
// If the environment asks us to actually be rustc, then do that.
446446
if let Some(crate_kind) = env::var_os("MIRI_BE_RUSTC") {
447447
// Earliest rustc setup.
@@ -751,11 +751,7 @@ fn main() {
751751
debug!("crate arguments: {:?}", miri_config.args);
752752
if !miri_config.native_lib.is_empty() && miri_config.native_lib_enable_tracing {
753753
// FIXME(ptrace): This should display a diagnostic / warning on error
754-
// SAFETY: If any other threads exist at this point (namely for the ctrlc
755-
// handler), they will not interact with anything on the main rustc/Miri
756-
// thread in an async-signal-unsafe way such as by accessing shared
757-
// semaphores, etc.; the handler only calls `sleep()` and `exit()`, which
758-
// are async-signal-safe, as is accessing atomics
754+
// SAFETY: No other threads are running
759755
let _ = unsafe { miri::native_lib::init_sv() };
760756
}
761757
run_compiler_and_exit(

src/shims/native_lib/mod.rs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,6 @@ use rustc_middle::mir::interpret::Pointer;
99
use rustc_middle::ty::{self as ty, IntTy, UintTy};
1010
use rustc_span::Symbol;
1111

12-
#[cfg_attr(
13-
all(
14-
target_os = "linux",
15-
target_env = "gnu",
16-
any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")
17-
),
18-
path = "trace/mod.rs"
19-
)]
2012
#[cfg_attr(
2113
not(all(
2214
target_os = "linux",
@@ -41,10 +33,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
4133
libffi_args: Vec<libffi::high::Arg<'a>>,
4234
) -> trace::CallResult<'tcx> {
4335
let this = self.eval_context_mut();
36+
#[cfg(target_os = "linux")]
4437
let alloc = this.machine.allocator.as_ref().unwrap();
4538

4639
// SAFETY: We don't touch the machine memory past this point.
47-
let (guard, stack_ptr) = unsafe { Supervisor::start_ffi(alloc) };
40+
#[cfg(target_os = "linux")]
41+
let guard = unsafe { Supervisor::start_ffi(alloc) };
4842

4943
// Call the function (`ptr`) with arguments `libffi_args`, and obtain the return value
5044
// as the specified primitive integer type
@@ -118,8 +112,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
118112

119113
// SAFETY: We got the guard and stack pointer from start_ffi, and
120114
// the allocator is the same
121-
let events = unsafe { Supervisor::end_ffi(alloc, guard, stack_ptr) };
122-
//let events = None;
115+
let events = unsafe { Supervisor::end_ffi(guard) };
123116

124117
interp_ok((res?, events))
125118
}

src/shims/native_lib/trace/child.rs

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ use super::messages::{Confirmation, MemEvents, StartFfiInfo, TraceRequest};
1010
use super::parent::{ChildListener, sv_loop};
1111
use crate::alloc::isolated_alloc::IsolatedAlloc;
1212

13+
/// A handle to the single, shared supervisor process across all `MiriMachine`s.
14+
/// Since it would be very difficult to trace multiple FFI calls in parallel, we
15+
/// need to ensure that either (a) only one `MiriMachine` is performing an FFI call
16+
/// at any given time, or (b) there are distinct supervisor and child processes for
17+
/// each machine. The former was chosen here.
1318
static SUPERVISOR: std::sync::Mutex<Option<Supervisor>> = std::sync::Mutex::new(None);
1419

1520
/// The main means of communication between the child and parent process,
@@ -24,6 +29,12 @@ pub struct Supervisor {
2429
event_rx: ipc::IpcReceiver<MemEvents>,
2530
}
2631

32+
pub struct SvFfiGuard<'a> {
33+
alloc: &'a Rc<RefCell<IsolatedAlloc>>,
34+
sv_guard: std::sync::MutexGuard<'static, Option<Supervisor>>,
35+
cb_stack: Option<*mut [u8; CALLBACK_STACK_SIZE]>,
36+
}
37+
2738
/// Marker representing that an error occurred during creation of the supervisor.
2839
#[derive(Debug)]
2940
pub struct SvInitError;
@@ -46,20 +57,24 @@ impl Supervisor {
4657
/// after the desired call has concluded.
4758
pub unsafe fn start_ffi(
4859
alloc: &Rc<RefCell<IsolatedAlloc>>,
49-
) -> (std::sync::MutexGuard<'static, Option<Supervisor>>, Option<*mut [u8; CALLBACK_STACK_SIZE]>)
60+
) -> SvFfiGuard<'_>
5061
{
5162
let mut sv_guard = SUPERVISOR.lock().unwrap();
5263
// If the supervisor is not initialised for whatever reason, fast-return.
5364
// This might be desired behaviour, as even on platforms where ptracing
5465
// is not implemented it enables us to enforce that only one FFI call
5566
// happens at a time.
5667
let Some(sv) = sv_guard.as_mut() else {
57-
return (sv_guard, None);
68+
return SvFfiGuard {
69+
alloc,
70+
sv_guard,
71+
cb_stack: None,
72+
};
5873
};
5974

6075
// Get pointers to all the pages the supervisor must allow accesses in
6176
// and prepare the callback stack.
62-
let page_ptrs = alloc.borrow().pages();
77+
let page_ptrs = alloc.borrow().pages().collect();
6378
let raw_stack_ptr: *mut [u8; CALLBACK_STACK_SIZE] =
6479
Box::leak(Box::new([0u8; CALLBACK_STACK_SIZE])).as_mut_ptr().cast();
6580
let stack_ptr = raw_stack_ptr.expose_provenance();
@@ -86,7 +101,11 @@ impl Supervisor {
86101
// modifications to our memory - simply waiting on the recv() doesn't
87102
// count.
88103
signal::raise(signal::SIGSTOP).unwrap();
89-
(sv_guard, Some(raw_stack_ptr))
104+
SvFfiGuard {
105+
alloc,
106+
sv_guard,
107+
cb_stack: Some(raw_stack_ptr),
108+
}
90109
}
91110

92111
/// Undoes FFI-related preparations, allowing Miri to continue as normal, then
@@ -98,10 +117,12 @@ impl Supervisor {
98117
/// received by a prior call to `start_ffi`, and the allocator must be the
99118
/// one passed to it also.
100119
pub unsafe fn end_ffi(
101-
alloc: &Rc<RefCell<IsolatedAlloc>>,
102-
mut sv_guard: std::sync::MutexGuard<'static, Option<Supervisor>>,
103-
raw_stack_ptr: Option<*mut [u8; CALLBACK_STACK_SIZE]>,
120+
guard: SvFfiGuard<'_>,
104121
) -> Option<MemEvents> {
122+
let alloc = guard.alloc;
123+
let mut sv_guard = guard.sv_guard;
124+
let cb_stack = guard.cb_stack;
125+
105126
// We can't use IPC channels here to signal that FFI mode has ended,
106127
// since they might allocate memory which could get us stuck in a SIGTRAP
107128
// with no easy way out! While this could be worked around, it is much
@@ -121,7 +142,7 @@ impl Supervisor {
121142
// SAFETY: Caller upholds that this pointer was allocated as a box with
122143
// this type.
123144
unsafe {
124-
drop(Box::from_raw(raw_stack_ptr.unwrap()));
145+
drop(Box::from_raw(cb_stack.unwrap()));
125146
}
126147
// On the off-chance something really weird happens, don't block forever.
127148
sv.event_rx
@@ -130,7 +151,7 @@ impl Supervisor {
130151
match e {
131152
ipc::TryRecvError::IpcError(_) => (),
132153
ipc::TryRecvError::Empty =>
133-
eprintln!("Waiting for accesses from supervisor timed out!"),
154+
panic!("Waiting for accesses from supervisor timed out!"),
134155
}
135156
})
136157
.ok()
@@ -141,6 +162,10 @@ impl Supervisor {
141162
/// supervisor process could not be created successfully; else, the caller
142163
/// is now the child process and can communicate via `start_ffi`/`end_ffi`,
143164
/// receiving back events through `get_events`.
165+
///
166+
/// When forking to initialise the supervisor, the child raises a `SIGSTOP`; if
167+
/// the parent successfully ptraces the child, it will allow it to resume. Else,
168+
/// the child will be killed by the parent.
144169
///
145170
/// # Safety
146171
/// The invariants for `fork()` must be upheld by the caller, namely either:
@@ -151,11 +176,6 @@ pub unsafe fn init_sv() -> Result<(), SvInitError> {
151176
// FIXME: Much of this could be reimplemented via the mitosis crate if we upstream the
152177
// relevant missing bits.
153178

154-
// Not on a properly supported architecture!
155-
if cfg!(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64"))) {
156-
return Err(SvInitError);
157-
}
158-
159179
// On Linux, this will check whether ptrace is fully disabled by the Yama module.
160180
// If Yama isn't running or we're not on Linux, we'll still error later, but
161181
// this saves a very expensive fork call.

src/shims/native_lib/trace/messages.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
//! Houses the types that are directly sent across the IPC channels.
2+
//!
23
//!
3-
//! The overall structure of a traced FFI call, from the child process's POV, is
4-
//! as follows:
4+
//! After initialisation is done, the overall structure of a traced FFI call from
5+
//! the child process's POV is as follows:
56
//! ```
67
//! message_tx.send(TraceRequest::StartFfi);
78
//! confirm_rx.recv();

src/shims/native_lib/trace/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ mod parent;
55
pub use self::child::{Supervisor, init_sv, register_retcode_sv};
66

77
/// The size of the temporary stack we use for callbacks that the server executes in the client.
8+
/// This should be big enough that `mempr_on` and `mempr_off` can safely be jumped into with the
9+
/// stack pointer pointing to a "stack" of this size without overflowing it.
810
const CALLBACK_STACK_SIZE: usize = 1024;
911

1012
pub(super) type CallResult<'tcx> = rustc_const_eval::interpret::InterpResult<

src/shims/native_lib/trace_stub.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,10 @@ impl Supervisor {
1010
}
1111

1212
#[inline(always)]
13-
pub unsafe fn start_ffi<T>(_: T) -> ((), ()) {
14-
((), ())
15-
}
13+
pub unsafe fn start_ffi<T>(_: T) {}
1614

1715
#[inline(always)]
18-
pub unsafe fn end_ffi<T, U, V>(_: T, _: U, _: V) -> Option<!> {
16+
pub unsafe fn end_ffi<T>(_: T) -> Option<!> {
1917
None
2018
}
2119
}

0 commit comments

Comments
 (0)