Skip to content

Commit

Permalink
Merge pull request #50 from multiversx/fix-capi-safe-unwind
Browse files Browse the repository at this point in the history
safe c-api unwind wrapper
  • Loading branch information
laurci authored Dec 16, 2024
2 parents 448510d + 2dae470 commit 2ad13f0
Show file tree
Hide file tree
Showing 13 changed files with 86 additions and 8 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
resolver = "2"

members = [
"meta",
"c-api",
"vm-executor",
"vm-executor-wasmer",
Expand Down
1 change: 1 addition & 0 deletions c-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ publish = false
crate-type = ["cdylib"]

[dependencies]
meta = { path = "../meta" }
multiversx-chain-vm-executor = { path = "../vm-executor" }
multiversx-chain-vm-executor-wasmer = { path = "../vm-executor-wasmer" }

Expand Down
2 changes: 2 additions & 0 deletions c-api/src/basic_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub enum vm_exec_result_t {
VM_EXEC_ERROR = 2,
}

#[allow(non_camel_case_types)]
#[repr(C)]
pub struct vm_exec_byte_array {
pub bytes: *const u8,
Expand Down Expand Up @@ -74,6 +75,7 @@ pub(crate) unsafe fn string_copy(
s.len() as c_int + 1
}

#[allow(non_camel_case_types)]
#[repr(C)]
pub struct vm_exec_byte_array_list {
pub arrays: *const vm_exec_byte_array,
Expand Down
3 changes: 3 additions & 0 deletions c-api/src/capi_breakpoints.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use meta::capi_safe_unwind;
use multiversx_chain_vm_executor::Instance;

use crate::capi_instance::{vm_exec_instance_t, CapiInstance};
Expand All @@ -15,6 +16,7 @@ use crate::vm_exec_result_t;
/// C API function, works with raw object pointers.
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
#[capi_safe_unwind(vm_exec_result_t::VM_EXEC_ERROR)]
pub unsafe extern "C" fn vm_exec_instance_set_breakpoint_value(
instance_ptr: *const vm_exec_instance_t,
value: u64,
Expand All @@ -37,6 +39,7 @@ pub unsafe extern "C" fn vm_exec_instance_set_breakpoint_value(
/// C API function, works with raw object pointers.
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
#[capi_safe_unwind(0)]
pub unsafe extern "C" fn vm_exec_instance_get_breakpoint_value(
instance_ptr: *const vm_exec_instance_t,
) -> u64 {
Expand Down
25 changes: 18 additions & 7 deletions c-api/src/capi_executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ use crate::{
service_singleton::with_service, vm_exec_result_t,
};
use libc::c_void;
use meta::capi_safe_unwind;
use multiversx_chain_vm_executor::Executor;
use multiversx_chain_vm_executor_wasmer::force_sighandler_reinstall;

#[allow(non_camel_case_types)]
#[repr(C)]
pub struct vm_exec_executor_t;

Expand All @@ -22,6 +24,7 @@ pub struct CapiExecutor {
/// C API function, works with raw object pointers.
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
#[capi_safe_unwind(vm_exec_result_t::VM_EXEC_ERROR)]
pub unsafe extern "C" fn vm_exec_new_executor(
executor: *mut *mut vm_exec_executor_t,
vm_hook_pointers_ptr_ptr: *mut *mut vm_exec_vm_hook_c_func_pointers,
Expand Down Expand Up @@ -74,19 +77,27 @@ pub unsafe extern "C" fn vm_force_sighandler_reinstall() {
/// C API function, works with raw object pointers.
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
#[capi_safe_unwind(vm_exec_result_t::VM_EXEC_ERROR)]
pub unsafe extern "C" fn vm_exec_executor_set_vm_hooks_ptr(
executor_ptr: *mut vm_exec_executor_t,
vm_hooks_ptr: *mut c_void,
) -> vm_exec_result_t {
let capi_executor = cast_input_ptr!(executor_ptr, CapiExecutor, "executor ptr is null");
let result = std::panic::catch_unwind(|| {
let capi_executor = cast_input_ptr!(executor_ptr, CapiExecutor, "executor ptr is null");

let result = capi_executor.content.set_vm_hooks_ptr(vm_hooks_ptr);
match result {
Ok(()) => vm_exec_result_t::VM_EXEC_OK,
Err(message) => {
with_service(|service| service.update_last_error_str(message.to_string()));
vm_exec_result_t::VM_EXEC_ERROR
let result = capi_executor.content.set_vm_hooks_ptr(vm_hooks_ptr);
match result {
Ok(()) => vm_exec_result_t::VM_EXEC_OK,
Err(message) => {
with_service(|service| service.update_last_error_str(message.to_string()));
vm_exec_result_t::VM_EXEC_ERROR
}
}
});

match result {
Ok(result) => result,
Err(_) => vm_exec_result_t::VM_EXEC_ERROR,
}
}

Expand Down
10 changes: 10 additions & 0 deletions c-api/src/capi_instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::{
service_singleton::with_service,
string_copy, vm_exec_result_t,
};
use meta::capi_safe_unwind;
use libc::{c_char, c_int};
use multiversx_chain_vm_executor::{CompilationOptions, Instance};
use std::{ffi::CStr, slice};
Expand All @@ -14,9 +15,11 @@ use std::{ffi::CStr, slice};
/// A `wasmer_runtime::Instance` represents a WebAssembly instance. It
/// is generally generated by the `wasmer_instantiate()` function, or by
/// the `wasmer_module_instantiate()` function for the most common paths.
#[allow(non_camel_case_types)]
#[repr(C)]
pub struct vm_exec_instance_t;

#[allow(non_camel_case_types)]
#[repr(C)]
pub struct vm_exec_compilation_options_t;

Expand All @@ -33,6 +36,7 @@ pub struct CapiInstance {
/// C API function, works with raw object pointers.
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
#[capi_safe_unwind(vm_exec_result_t::VM_EXEC_ERROR)]
pub unsafe extern "C" fn vm_exec_new_instance(
executor_ptr: *mut vm_exec_executor_t,
instance_ptr_ptr: *mut *mut vm_exec_instance_t,
Expand Down Expand Up @@ -86,6 +90,7 @@ pub unsafe extern "C" fn vm_exec_new_instance(
/// C API function, works with raw object pointers.
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
#[capi_safe_unwind(vm_exec_result_t::VM_EXEC_ERROR)]
pub unsafe extern "C" fn vm_exec_instance_call(
instance_ptr: *mut vm_exec_instance_t,
func_name_ptr: *const c_char,
Expand Down Expand Up @@ -119,6 +124,7 @@ pub unsafe extern "C" fn vm_exec_instance_call(
/// C API function, works with raw object pointers.
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
#[capi_safe_unwind(vm_exec_result_t::VM_EXEC_ERROR)]
pub unsafe extern "C" fn vm_check_signatures(
instance_ptr: *mut vm_exec_instance_t,
) -> vm_exec_result_t {
Expand All @@ -142,6 +148,7 @@ pub unsafe extern "C" fn vm_check_signatures(
/// C API function, works with raw object pointers.
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
#[capi_safe_unwind(-1)]
pub unsafe extern "C" fn vm_exec_instance_has_function(
instance_ptr: *mut vm_exec_instance_t,
func_name_ptr: *const c_char,
Expand All @@ -163,6 +170,7 @@ pub unsafe extern "C" fn vm_exec_instance_has_function(
/// C API function, works with raw object pointers.
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
#[capi_safe_unwind(0)]
pub unsafe extern "C" fn vm_exported_function_names_length(
instance_ptr: *mut vm_exec_instance_t,
) -> c_int {
Expand Down Expand Up @@ -190,6 +198,7 @@ pub unsafe extern "C" fn vm_exported_function_names_length(
/// C API function, works with raw object pointers.
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
#[capi_safe_unwind(0)]
pub unsafe extern "C" fn vm_exported_function_names(
instance_ptr: *mut vm_exec_instance_t,
dest_buffer: *mut c_char,
Expand Down Expand Up @@ -228,6 +237,7 @@ pub unsafe extern "C" fn vm_exec_instance_destroy(instance_ptr: *mut vm_exec_ins
/// C API function, works with raw object pointers.
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
#[capi_safe_unwind(vm_exec_result_t::VM_EXEC_ERROR)]
pub unsafe extern "C" fn vm_exec_instance_reset(
instance_ptr: *mut vm_exec_instance_t,
) -> vm_exec_result_t {
Expand Down
3 changes: 3 additions & 0 deletions c-api/src/capi_instance_cache.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::slice;

use meta::capi_safe_unwind;
use multiversx_chain_vm_executor::CompilationOptions;

use crate::{
Expand All @@ -16,6 +17,7 @@ use crate::{
/// C API function, works with raw object pointers.
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
#[capi_safe_unwind(vm_exec_result_t::VM_EXEC_ERROR)]
pub unsafe extern "C" fn vm_exec_instance_cache(
instance_ptr: *const vm_exec_instance_t,
cache_bytes_ptr: *mut *const u8,
Expand Down Expand Up @@ -47,6 +49,7 @@ pub unsafe extern "C" fn vm_exec_instance_cache(
/// C API function, works with raw object pointers.
#[allow(clippy::cast_ptr_alignment, unused_variables)]
#[no_mangle]
#[capi_safe_unwind(vm_exec_result_t::VM_EXEC_ERROR)]
pub unsafe extern "C" fn vm_exec_instance_from_cache(
executor_ptr: *mut vm_exec_executor_t,
instance_ptr_ptr: *mut *mut vm_exec_instance_t,
Expand Down
2 changes: 2 additions & 0 deletions c-api/src/capi_logger.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use meta::capi_safe_unwind;
use multiversx_chain_vm_executor_wasmer::{set_log_level, u64_to_log_level};

use crate::{basic_types::vm_exec_result_t, service_singleton::with_service};

/// Sets the log level.
#[no_mangle]
#[capi_safe_unwind(vm_exec_result_t::VM_EXEC_ERROR)]
pub extern "C" fn vm_exec_set_log_level(value: u64) -> vm_exec_result_t {
let result = u64_to_log_level(value);

Expand Down
5 changes: 5 additions & 0 deletions c-api/src/capi_memory.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! Instantiate a module, call functions, and read exports.
use meta::capi_safe_unwind;

use crate::{
capi_instance::{vm_exec_instance_t, CapiInstance},
service_singleton::with_service,
Expand All @@ -16,6 +18,7 @@ use std::ptr;
/// C API function, works with raw object pointers.
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
#[capi_safe_unwind(0)]
pub unsafe extern "C" fn vm_exec_instance_memory_data_length(
instance_ptr: *mut vm_exec_instance_t,
) -> u64 {
Expand Down Expand Up @@ -43,6 +46,7 @@ pub unsafe extern "C" fn vm_exec_instance_memory_data_length(
/// C API function, works with raw object pointers.
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
#[capi_safe_unwind(ptr::null_mut())]
pub unsafe extern "C" fn vm_exec_instance_memory_data(
instance_ptr: *mut vm_exec_instance_t,
) -> *mut u8 {
Expand Down Expand Up @@ -74,6 +78,7 @@ pub unsafe extern "C" fn vm_exec_instance_memory_data(
/// C API function, works with raw object pointers.
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
#[capi_safe_unwind(vm_exec_result_t::VM_EXEC_ERROR)]
pub unsafe extern "C" fn vm_exec_instance_memory_grow(
instance_ptr: *mut vm_exec_instance_t,
by_num_pages: u32,
Expand Down
5 changes: 5 additions & 0 deletions c-api/src/capi_metering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::capi_executor::{vm_exec_executor_t, CapiExecutor};
use crate::capi_instance::{vm_exec_instance_t, CapiInstance};
use crate::service_singleton::with_service;
use crate::vm_exec_result_t;
use meta::capi_safe_unwind;
use multiversx_chain_vm_executor::OpcodeCost;

#[allow(non_camel_case_types)]
Expand All @@ -19,6 +20,7 @@ pub struct vm_exec_opcode_cost_t;
/// C API function, works with raw object pointers.
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
#[capi_safe_unwind(vm_exec_result_t::VM_EXEC_ERROR)]
pub unsafe extern "C" fn vm_exec_set_opcode_costs(
executor_ptr: *mut vm_exec_executor_t,
opcode_cost_ptr: *const vm_exec_opcode_cost_t,
Expand Down Expand Up @@ -47,6 +49,7 @@ pub unsafe extern "C" fn vm_exec_set_opcode_costs(
/// C API function, works with raw object pointers.
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
#[capi_safe_unwind(vm_exec_result_t::VM_EXEC_ERROR)]
pub unsafe extern "C" fn vm_exec_instance_set_points_limit(
instance_ptr: *const vm_exec_instance_t,
limit: u64,
Expand All @@ -73,6 +76,7 @@ pub unsafe extern "C" fn vm_exec_instance_set_points_limit(
/// C API function, works with raw object pointers.
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
#[capi_safe_unwind(vm_exec_result_t::VM_EXEC_ERROR)]
pub unsafe extern "C" fn vm_exec_instance_set_points_used(
instance_ptr: *const vm_exec_instance_t,
points: u64,
Expand All @@ -95,6 +99,7 @@ pub unsafe extern "C" fn vm_exec_instance_set_points_used(
/// C API function, works with raw object pointers.
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
#[capi_safe_unwind(0)]
pub unsafe extern "C" fn vm_exec_instance_get_points_used(
instance_ptr: *const vm_exec_instance_t,
) -> u64 {
Expand Down
2 changes: 1 addition & 1 deletion c-api/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,4 @@ macro_rules! cast_input_const_ptr {
vm_exec_result_t::VM_EXEC_ERROR
)
};
}
}
11 changes: 11 additions & 0 deletions meta/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "meta"
version = "0.1.0"
edition = "2021"

[lib]
proc-macro = true

[dependencies]
syn = "2.0.77"
quote = "1.0.9"
24 changes: 24 additions & 0 deletions meta/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use proc_macro::TokenStream;
use quote::quote;

#[proc_macro_attribute]
pub fn capi_safe_unwind(attr: TokenStream, item: TokenStream) -> TokenStream {
let func = syn::parse_macro_input!(item as syn::ItemFn);
let fail_return = syn::parse_macro_input!(attr as syn::Expr);

let signature = &func.sig;
let body = &func.block;
let attributes = &func.attrs;
let vis = &func.vis;

quote! {
#(#attributes)*
#vis #signature {
let result = std::panic::catch_unwind(|| #body);
match result {
Ok(result) => result,
Err(_) => #fail_return,
}
}
}.into()
}

0 comments on commit 2ad13f0

Please sign in to comment.