Skip to content

Commit 97082c7

Browse files
committed
fix: host_bindgen! returns Result instead of panicking on guest errors
The host_bindgen! macro generated export wrapper functions that would panic when Callable::call() returned Err (e.g., guest abort, trap, timeout). This crashed the host process. Signed-off-by: James Sturtevant <jsturtevant@gmail.com>
1 parent 4e0ea22 commit 97082c7

5 files changed

Lines changed: 215 additions & 94 deletions

File tree

src/hyperlight_component_util/src/host.rs

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ fn emit_export_extern_decl<'a, 'b, 'c>(
4646
.map(|p| rtypes::emit_func_param(s, p))
4747
.collect::<Vec<_>>();
4848
let result_decl = rtypes::emit_func_result(s, &ft.result);
49+
let result_decl = quote! { ::std::result::Result<#result_decl, ::hyperlight_host::error::HyperlightError> };
4950
let hln = emit_fn_hl_name(s, ed.kebab_name);
5051
let ret = format_ident!("ret");
5152
let marshal = ft
@@ -66,11 +67,11 @@ fn emit_export_extern_decl<'a, 'b, 'c>(
6667
#hln,
6768
marshalled,
6869
);
69-
let ::std::result::Result::Ok(#ret) = #ret else { panic!("bad return from guest {:?}", #ret) };
70+
let #ret = #ret?;
7071
#[allow(clippy::unused_unit)]
7172
let mut rts = self.rt.lock().unwrap();
7273
#[allow(clippy::unused_unit)]
73-
#unmarshal
74+
Ok(#unmarshal)
7475
}
7576
}
7677
}
@@ -215,17 +216,28 @@ fn emit_import_extern_decl<'a, 'b, 'c>(
215216
})
216217
.unzip::<_, _, Vec<_>, Vec<_>>();
217218
let tp = s.cur_trait_path();
218-
let callname = match kebab_to_fn(ed.kebab_name) {
219-
FnName::Plain(n) => quote! { #tp::#n },
219+
let (callname, is_constructor) = match kebab_to_fn(ed.kebab_name) {
220+
FnName::Plain(n) => (quote! { #tp::#n }, false),
220221
FnName::Associated(r, m) => {
221222
let hp = s.helper_path();
222223
match m {
223-
ResourceItemName::Constructor => quote! { #hp #r::new },
224-
ResourceItemName::Method(mn) => quote! { #hp #r::#mn },
225-
ResourceItemName::Static(mn) => quote! { #hp #r::#mn },
224+
ResourceItemName::Constructor => (quote! { #hp #r::new }, true),
225+
ResourceItemName::Method(mn) => (quote! { #hp #r::#mn }, false),
226+
ResourceItemName::Static(mn) => (quote! { #hp #r::#mn }, false),
226227
}
227228
}
228229
};
230+
// WIT constructors always return `own<resource>` with no
231+
// spec-level mechanism for fallibility, so their trait
232+
// signature stays as `fn new(...) -> Self::T` (no Result
233+
// wrapper). Non-constructor trait methods return
234+
// `Result` on the host side, so we append `?` to
235+
// propagate errors from the host implementation.
236+
let try_op = if is_constructor {
237+
quote! {}
238+
} else {
239+
quote! { ? }
240+
};
229241
let SelfInfo {
230242
orig_id,
231243
type_id,
@@ -246,7 +258,7 @@ fn emit_import_extern_decl<'a, 'b, 'c>(
246258
&mut #inner_id
247259
),
248260
#(#pus),*
249-
);
261+
)#try_op;
250262
Ok(#marshal_result)
251263
})
252264
.unwrap();

src/hyperlight_component_util/src/rtypes.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,11 @@ fn emit_extern_decl<'a, 'b, 'c>(
632632
.map(|p| emit_func_param(&mut s, p))
633633
.collect::<Vec<_>>();
634634
let result = emit_func_result(&mut s, &ft.result);
635+
let result = if !s.is_guest {
636+
quote! { ::std::result::Result<#result, ::hyperlight_host::error::HyperlightError> }
637+
} else {
638+
result
639+
};
635640
quote! {
636641
fn #n(&mut self, #(#params),*) -> #result;
637642
}
@@ -654,12 +659,22 @@ fn emit_extern_decl<'a, 'b, 'c>(
654659
}
655660
ResourceItemName::Method(n) => {
656661
let result = emit_func_result(&mut sv, &ft.result);
662+
let result = if !sv.is_guest {
663+
quote! { ::std::result::Result<#result, ::hyperlight_host::error::HyperlightError> }
664+
} else {
665+
result
666+
};
657667
sv.cur_trait().items.extend(quote! {
658668
fn #n(&mut self, #(#params),*) -> #result;
659669
});
660670
}
661671
ResourceItemName::Static(n) => {
662672
let result = emit_func_result(&mut sv, &ft.result);
673+
let result = if !sv.is_guest {
674+
quote! { ::std::result::Result<#result, ::hyperlight_host::error::HyperlightError> }
675+
} else {
676+
result
677+
};
663678
sv.cur_trait().items.extend(quote! {
664679
fn #n(&mut self, #(#params),*) -> #result;
665680
});

0 commit comments

Comments
 (0)