From 63b1a9f8d5964c065ef81b7cc510eb2164182bab Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Wed, 11 Sep 2024 02:25:57 +1000 Subject: [PATCH] Fixes for Rust 1.81.0 (#1333) ### What Fixes for Rust 1.81: 1. Update semver-checks to 0.35.0. 2. Don't use the `extern` function for invoking a contract function when executing tests. ### Why 1. Semver checks is failing to run on the new version of Rust and needs updating. 2. Rust 1.81.0 changed the behavior of panics on `extern "C"` functions, such that panics cannot be caught by [std::panic::catch_unwind](https://doc.rust-lang.org/std/panic/fn.catch_unwind.html). Contracts expose their functions as an `extern` function that defaults to `extern "C"`. The test environment catches panics inside contract functions and resurfaces them as errors by using catch_unwind. The solution used was to make it so that the test environment never calls through the extern function, and instead calls through a non-extern function that does the same work. This seems like the sanest way to take away any dependence / relationship between the test environment and the Rust C-ABI so that any future changes to the C-ABI don't affect the test environment. An alternative solution would be to mark the contract function as `extern "C-unwind"` so that it retained unwind functionality, but that would continue to bind the SDK test environment to behaviour changes in extern fns. In the solution in this change the Abi qualifier `"C"` has been added. When the Abi qualifier is not specified it defaults to `"C"`, but for the sake of being explicit and removing any doubt from a reader it is now specified. The Rust reference confirms that `"C"` is the default: - https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier. More details on this change to Rust 1.81.0 can be found at: - https://blog.rust-lang.org/2024/09/05/Rust-1.81.0.html#abort-on-uncaught-panics-in-extern-c-functions - https://github.com/rust-lang/rust/issues/74990 Close #1332 --- .github/workflows/rust.yml | 4 ++-- soroban-sdk-macros/src/derive_fn.rs | 17 ++++++++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 3b524f9bd..ebde4e671 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -57,10 +57,10 @@ jobs: steps: - uses: actions/checkout@v3 - run: rustup update - - uses: stellar/binaries@v24 + - uses: stellar/binaries@v30 with: name: cargo-semver-checks - version: 0.32.0 + version: 0.35.0 - run: cargo semver-checks build-and-test: diff --git a/soroban-sdk-macros/src/derive_fn.rs b/soroban-sdk-macros/src/derive_fn.rs index 168d8b0fc..63745a7a5 100644 --- a/soroban-sdk-macros/src/derive_fn.rs +++ b/soroban-sdk-macros/src/derive_fn.rs @@ -50,7 +50,7 @@ pub fn derive_pub_fn( }); // Prepare the argument inputs. - let (wrap_args, wrap_calls): (Vec<_>, Vec<_>) = inputs + let (wrap_args, passthrough_calls, wrap_calls): (Vec<_>, Vec<_>, Vec<_>) = inputs .iter() .skip(if env_input.is_some() { 1 } else { 0 }) .enumerate() @@ -78,6 +78,7 @@ pub fn derive_pub_fn( colon_token: Colon::default(), ty: Box::new(Type::Verbatim(quote! { #crate_path::Val })), }); + let passthrough_call = quote! { #ident }; let call = quote! { <_ as #crate_path::unwrap::UnwrapOptimized>::unwrap_optimized( <_ as #crate_path::TryFromValForContractFn<#crate_path::Env, #crate_path::Val>>::try_from_val_for_contract_fn( @@ -86,11 +87,11 @@ pub fn derive_pub_fn( ) ) }; - (arg, call) + (arg, passthrough_call, call) } FnArg::Receiver(_) => { errors.push(Error::new(a.span(), "self argument not supported")); - (a.clone(), quote! {}) + (a.clone(), quote! {}, quote! {}) } }) .multiunzip(); @@ -132,8 +133,7 @@ pub fn derive_pub_fn( use super::*; #[deprecated(note = #deprecated_note)] - #[cfg_attr(target_family = "wasm", export_name = #wrap_export_name)] - pub extern fn invoke_raw(env: #crate_path::Env, #(#wrap_args),*) -> #crate_path::Val { + pub fn invoke_raw(env: #crate_path::Env, #(#wrap_args),*) -> #crate_path::Val { #use_trait; <_ as #crate_path::IntoVal<#crate_path::Env, #crate_path::Val>>::into_val( #[allow(deprecated)] @@ -154,6 +154,13 @@ pub fn derive_pub_fn( invoke_raw(env, #(#slice_args),*) } + #[deprecated(note = #deprecated_note)] + #[cfg_attr(target_family = "wasm", export_name = #wrap_export_name)] + pub extern "C" fn invoke_raw_extern(env: #crate_path::Env, #(#wrap_args),*) -> #crate_path::Val { + #[allow(deprecated)] + invoke_raw(env, #(#passthrough_calls),*) + } + use super::*; } })