Skip to content

Commit 19a0946

Browse files
authored
Debug: clarify safety around ActivationBacktrace::new. (#12191)
* Debug: clarify safety around ActivationBacktrace::new. As per [this discussion], we decided that we would handle potential frame-cursor invalidation unsafety (with a hypothetical future frame-editing debugger API) by putting `unsafe` on that future hypothetical API rather than on the cursor construction. With the APIs available today on the `Store`, there is no way to invalidate the frame cursor while within its lifetime-bounded scope (with lifetime tied to the `Store` that is passed into the hostcall creating the cursor), so the API today should be completely safe. This PR makes it so. [this discussion]: #12176 (comment) * store_mut is safe as well.
1 parent c9a764e commit 19a0946

File tree

2 files changed

+10
-44
lines changed

2 files changed

+10
-44
lines changed

crates/wasmtime/src/runtime/debug.rs

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -153,12 +153,7 @@ impl<'a, T: 'static> DebugFrameCursor<'a, T> {
153153
};
154154
self.frames = match next_frame {
155155
FrameOrHostCode::Frame(frame) => VirtualFrame::decode(
156-
// SAFETY: we are using the Store only to decode
157-
// frames; the only mutable aspect used here is
158-
// rooting any new GC values that are read out,
159-
// and we do not remove frames that we may be
160-
// visiting.
161-
unsafe { self.iter.store_mut() }.0.as_store_opaque(),
156+
self.iter.store_mut().0.as_store_opaque(),
162157
frame,
163158
self.is_trapping_frame,
164159
),
@@ -203,14 +198,7 @@ impl<'a, T: 'static> DebugFrameCursor<'a, T> {
203198
/// Get the instance associated with the current frame.
204199
pub fn instance(&mut self) -> Instance {
205200
let instance = self.raw_instance();
206-
Instance::from_wasmtime(
207-
instance.id(),
208-
// SAFETY: we are using the Store only
209-
// to read the instance reference; we
210-
// do not remove frames that we may be
211-
// visiting.
212-
unsafe { self.iter.store_mut() }.0.as_store_opaque(),
213-
)
201+
Instance::from_wasmtime(instance.id(), self.iter.store_mut().0.as_store_opaque())
214202
}
215203

216204
/// Get the module associated with the current frame, if any
@@ -505,10 +493,7 @@ impl<'a, T: 'static> AsContext for DebugFrameCursor<'a, T> {
505493
}
506494
impl<'a, T: 'static> AsContextMut for DebugFrameCursor<'a, T> {
507495
fn as_context_mut(&mut self) -> StoreContextMut<'_, Self::Data> {
508-
// SAFETY: `StoreContextMut` does not provide any methods that
509-
// could remove frames from the stack, so the iterator remains
510-
// valid.
511-
unsafe { StoreContextMut(self.iter.store_mut().0) }
496+
StoreContextMut(self.iter.store_mut().0)
512497
}
513498
}
514499

crates/wasmtime/src/runtime/vm/traphandlers/backtrace.rs

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -407,19 +407,7 @@ impl<'a, T: 'static> ActivationBacktrace<'a, T> {
407407
/// This serves as an alternative to `Backtrace::trace()` and
408408
/// friends: it allows external iteration (and e.g. lazily walking
409409
/// through frames in a stack) rather than visiting via a closure.
410-
///
411-
/// # Safety
412-
///
413-
/// Although the iterator provides mutable store as a public
414-
/// field, this *must not* be used to mutate the stack activation
415-
/// itself that this iterator is visiting. While the `store`
416-
/// technically owns the stack in question, the only way to do
417-
/// this with the current API would be to return back into the
418-
/// Wasm activation. As long as this iterator is held and used
419-
/// while within host code called from that activation (which will
420-
/// ordinarily be ensured if the `store`'s lifetime came from the
421-
/// host entry point) then everything will be sound.
422-
pub(crate) unsafe fn new(
410+
pub(crate) fn new(
423411
store: StoreContextMut<'a, T>,
424412
activation: Activation,
425413
) -> ActivationBacktrace<'a, T> {
@@ -506,9 +494,9 @@ impl<'a, T> StoreBacktrace<'a, T> {
506494
// the innermost activation that owns the store, or a sentinel
507495
// if there are no activations.
508496
let current = match activations.pop() {
509-
Some(innermost) => unsafe {
497+
Some(innermost) => {
510498
StoreOrActivationBacktrace::Activation(ActivationBacktrace::new(store, innermost))
511-
},
499+
}
512500
None => StoreOrActivationBacktrace::Store(store),
513501
};
514502
StoreBacktrace {
@@ -526,14 +514,7 @@ impl<'a, T> StoreBacktrace<'a, T> {
526514
}
527515

528516
/// Get the Store underlying this iteration.
529-
///
530-
/// # Safety
531-
///
532-
/// This mutable store access *must not* be used to mutate the
533-
/// stack itself that this iterator is visiting by removing
534-
/// frames, even though the `store` technically owns the stack in
535-
/// question.
536-
pub unsafe fn store_mut(&mut self) -> StoreContextMut<'_, T> {
517+
pub fn store_mut(&mut self) -> StoreContextMut<'_, T> {
537518
match self.current.as_mut().unwrap() {
538519
StoreOrActivationBacktrace::Activation(activation) => {
539520
StoreContextMut(activation.store.0)
@@ -554,9 +535,9 @@ impl<'a, T> StoreBacktrace<'a, T> {
554535
let activation = self.activations.pop();
555536
let store = self.take_store();
556537
self.current = Some(match activation {
557-
Some(activation) => StoreOrActivationBacktrace::Activation(unsafe {
558-
ActivationBacktrace::new(store, activation)
559-
}),
538+
Some(activation) => {
539+
StoreOrActivationBacktrace::Activation(ActivationBacktrace::new(store, activation))
540+
}
560541
None => StoreOrActivationBacktrace::Store(store),
561542
});
562543
}

0 commit comments

Comments
 (0)