Skip to content

Commit 93cefa7

Browse files
fixup! retain error
1 parent 45ebe6d commit 93cefa7

2 files changed

Lines changed: 33 additions & 45 deletions

File tree

ext/src/ruby_api/store.rs

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use super::errors::wasi_exit_error;
22
use super::{caller::Caller, engine::Engine, root, trap::Trap};
3+
use crate::ruby_api::wasi_config::WasiRetainedData;
34
use crate::{define_rb_intern, error, WasiConfig};
45
use magnus::value::ReprValue;
56
use magnus::value::StaticSymbol;
@@ -36,6 +37,7 @@ pub struct StoreData {
3637
wasi_p1: Option<WasiP1Ctx>,
3738
wasi: Option<WasiCtx>,
3839
refs: Vec<Value>,
40+
wasi_retained_data: Option<WasiRetainedData>,
3941
last_error: Option<Error>,
4042
store_limits: TrackingResourceLimiter,
4143
resource_table: ResourceTable,
@@ -73,26 +75,19 @@ impl StoreData {
7375
}
7476

7577
pub fn check_socket_errors(&mut self) {
76-
use crate::ruby_api::wasi_config::WasiRetainedData;
77-
78-
// Check all retained values for WasiRetainedData and extract error storages
79-
for value in &self.refs {
80-
let ruby = Ruby::get().unwrap();
81-
82-
// Try to convert to WasiRetainedData
83-
if let Ok(retained) = Obj::<WasiRetainedData>::try_convert(*value) {
84-
if let Some(storage) = retained.error_storage() {
85-
if let Ok(mut guard) = storage.lock() {
86-
if let Some((class_name, error_msg)) = guard.take() {
87-
// Look up the exception class by name and reconstruct the error
88-
let exception_class = ruby
89-
.class_object()
90-
.const_get::<_, ExceptionClass>(class_name)
91-
.unwrap_or_else(|_| ruby.exception_runtime_error());
92-
93-
self.last_error = Some(Error::new(exception_class, error_msg));
94-
return;
95-
}
78+
// Check the wasi_retained_data field for stored socket errors
79+
if let Some(ref retained_data) = self.wasi_retained_data {
80+
if let Some(storage) = retained_data.error_storage() {
81+
if let Ok(mut guard) = storage.lock() {
82+
if let Some((class_name, error_msg)) = guard.take() {
83+
let ruby = Ruby::get().unwrap();
84+
// Look up the exception class by name and reconstruct the error
85+
let exception_class = ruby
86+
.class_object()
87+
.const_get::<_, ExceptionClass>(class_name)
88+
.unwrap_or_else(|_| ruby.exception_runtime_error());
89+
90+
self.last_error = Some(Error::new(exception_class, error_msg));
9691
}
9792
}
9893
}
@@ -108,6 +103,10 @@ impl StoreData {
108103
}
109104
}
110105

106+
if let Some(ref retained_data) = self.wasi_retained_data {
107+
retained_data.mark(marker);
108+
}
109+
111110
for value in self.refs.iter() {
112111
marker.mark_movable(*value);
113112
}
@@ -205,12 +204,9 @@ impl Store {
205204
.transpose()?
206205
.unzip();
207206

208-
// Collect any Values that need to be retained for GC
209-
let refs: Vec<Value> = [wasi_retained, wasi_p1_retained]
210-
.into_iter()
211-
.flatten()
212-
.flatten()
213-
.collect();
207+
// Store WasiRetainedData directly (prefer wasi over wasi_p1 if both present)
208+
let wasi_retained_data: Option<WasiRetainedData> =
209+
wasi_retained.flatten().or(wasi_p1_retained.flatten());
214210

215211
let limiter = match kw.optional.2 {
216212
None => StoreLimitsBuilder::new(),
@@ -224,7 +220,8 @@ impl Store {
224220
user_data,
225221
wasi_p1,
226222
wasi,
227-
refs,
223+
refs: Default::default(),
224+
wasi_retained_data,
228225
last_error: Default::default(),
229226
store_limits: limiter,
230227
resource_table: Default::default(),

ext/src/ruby_api/wasi_config.rs

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -35,22 +35,17 @@ type SocketErrorStorage = Arc<Mutex<Option<(String, String)>>>;
3535

3636
/// Container for data that needs to be retained by the Store for WASI functionality.
3737
/// This includes Ruby procs (for GC marking) and error storages (for error propagation).
38-
#[derive(TypedData)]
39-
#[magnus(class = "Wasmtime::WasiRetainedData", mark, free_immediately)]
4038
pub struct WasiRetainedData {
4139
proc: Option<Opaque<Proc>>,
4240
error_storage: Option<SocketErrorStorage>,
4341
}
4442

45-
impl DataTypeFunctions for WasiRetainedData {
46-
fn mark(&self, marker: &Marker) {
43+
impl WasiRetainedData {
44+
pub fn mark(&self, marker: &Marker) {
4745
if let Some(proc) = self.proc {
4846
marker.mark(proc);
4947
}
5048
}
51-
}
52-
53-
impl WasiRetainedData {
5449
pub fn new(proc: Option<Proc>, error_storage: Option<SocketErrorStorage>) -> Self {
5550
Self {
5651
proc: proc.map(|p| p.into()),
@@ -505,19 +500,19 @@ impl WasiConfig {
505500
rb_self
506501
}
507502

508-
pub fn build_p1(&self, ruby: &Ruby) -> Result<(WasiP1Ctx, Option<Value>), Error> {
503+
pub fn build_p1(&self, ruby: &Ruby) -> Result<(WasiP1Ctx, Option<WasiRetainedData>), Error> {
509504
let (mut builder, retained_data) = self.build_impl(ruby)?;
510505
let ctx = builder.build_p1();
511506
Ok((ctx, retained_data))
512507
}
513508

514-
pub fn build(&self, ruby: &Ruby) -> Result<(WasiCtx, Option<Value>), Error> {
509+
pub fn build(&self, ruby: &Ruby) -> Result<(WasiCtx, Option<WasiRetainedData>), Error> {
515510
let (mut builder, retained_data) = self.build_impl(ruby)?;
516511
let ctx = builder.build();
517512
Ok((ctx, retained_data))
518513
}
519514

520-
fn build_impl(&self, ruby: &Ruby) -> Result<(WasiCtxBuilder, Option<Value>), Error> {
515+
fn build_impl(&self, ruby: &Ruby) -> Result<(WasiCtxBuilder, Option<WasiRetainedData>), Error> {
521516
let mut builder = WasiCtxBuilder::new();
522517
let inner = self.inner.borrow();
523518
let mut proc_to_retain = None;
@@ -631,15 +626,14 @@ impl WasiConfig {
631626
.map_err(|e| error!("{}", e))?;
632627
}
633628

634-
// Wrap retained data in a single Ruby object if we have anything to retain
635-
let retained_value = if proc_to_retain.is_some() || error_storage_to_retain.is_some() {
636-
let retained_data = WasiRetainedData::new(proc_to_retain, error_storage_to_retain);
637-
Some(ruby.obj_wrap(retained_data).as_value())
629+
// Return retained data directly if we have anything to retain
630+
let retained_data = if proc_to_retain.is_some() || error_storage_to_retain.is_some() {
631+
Some(WasiRetainedData::new(proc_to_retain, error_storage_to_retain))
638632
} else {
639633
None
640634
};
641635

642-
Ok((builder, retained_value))
636+
Ok((builder, retained_data))
643637
}
644638

645639
fn check_determinism(&self) -> Result<(), Error> {
@@ -671,9 +665,6 @@ pub fn file_w(path: RString) -> Result<File, Error> {
671665
}
672666

673667
pub fn init(ruby: &Ruby) -> Result<(), Error> {
674-
// Register internal WasiRetainedData class (not exposed to Ruby API)
675-
root().define_class("WasiRetainedData", ruby.class_object())?;
676-
677668
let class = root().define_class("WasiConfig", ruby.class_object())?;
678669
class.define_singleton_method("new", function!(WasiConfig::new, 0))?;
679670

0 commit comments

Comments
 (0)