Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rust 2024: uniffi_reexport_scaffolding: usage of unsafe attribute #2459

Open
bes opened this issue Mar 1, 2025 · 12 comments
Open

Rust 2024: uniffi_reexport_scaffolding: usage of unsafe attribute #2459

bes opened this issue Mar 1, 2025 · 12 comments

Comments

@bes
Copy link

bes commented Mar 1, 2025

I am trying to migrate a large project to Rust 2024, but I'm running into a small SNAFU.

I have two crates exporting uniffi types: A main crate and a helper crate with models. When trying to use the uniffi_reexport_scaffolding macro I get the following error:

error: unsafe attribute used without unsafe
  --> src/lib.rs:14:1
   |
14 | models::uniffi_reexport_scaffolding!();
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ usage of unsafe attribute
   |
   = note: this error originates in the macro `models::uniffi_reexport_scaffolding` (in Nightly builds, run with -Z macro-backtrace for more info)
help: wrap the attribute in `unsafe(...)`
  --> models/src/lib.rs:5:3
   |
5  | ununsafe(iffi::setup_scaffolding!("models"));
   |   +++++++                                 +

(note the nonsensical placement of unsafe recommended by rust on the second to last line)

Any ideas / recommendations? Thanks!

@bes
Copy link
Author

bes commented Mar 1, 2025

For reference this is the way I call the scaffolding macros:

uniffi::setup_scaffolding!("ffi");
#[cfg(target_os = "ios")]
models::uniffi_reexport_scaffolding!();

@bes
Copy link
Author

bes commented Mar 1, 2025

And I am using uniffi version 0.29.0

@mhammond
Copy link
Member

mhammond commented Mar 2, 2025

see #2447

@mhammond
Copy link
Member

mhammond commented Mar 6, 2025

#2447 has landed, is it possible for you to test the current git version so check your problem has been resolved?

@bes
Copy link
Author

bes commented Mar 7, 2025

@mhammond Doesn't work, unless I also apply this (locally):

diff --git a/uniffi_macros/src/export/callback_interface.rs b/uniffi_macros/src/export/callback_interface.rs
index 6c9fd8913..44ac04cf0 100644
--- a/uniffi_macros/src/export/callback_interface.rs
+++ b/uniffi_macros/src/export/callback_interface.rs
@@ -87,7 +87,7 @@ pub(super) fn trait_impl(
 
         static #vtable_cell: ::uniffi::UniffiForeignPointerCell::<#vtable_type> = ::uniffi::UniffiForeignPointerCell::<#vtable_type>::new();
 
-        #[no_mangle]
+        #[unsafe(no_mangle)]
         pub extern "C" fn #init_ident(vtable: ::std::ptr::NonNull<#vtable_type>) {
             #vtable_cell.set(vtable);
         }
diff --git a/uniffi_macros/src/export/scaffolding.rs b/uniffi_macros/src/export/scaffolding.rs
index 692ab4a41..d2463cbf9 100644
--- a/uniffi_macros/src/export/scaffolding.rs
+++ b/uniffi_macros/src/export/scaffolding.rs
@@ -252,7 +252,7 @@ pub(super) fn gen_ffi_function(
             ffi_buffer_scaffolding_fn(&ffi_ident, &ffi_return_ty, &param_types, true);
         quote! {
             #[doc(hidden)]
-            #[no_mangle]
+            #[unsafe(no_mangle)]
             pub extern "C" fn #ffi_ident(
                 #(#param_names: #param_types,)*
                 call_status: &mut ::uniffi::RustCallStatus,
@@ -287,7 +287,7 @@ pub(super) fn gen_ffi_function(
 
         quote! {
             #[doc(hidden)]
-            #[no_mangle]
+            #[unsafe(no_mangle)]
             pub extern "C" fn #ffi_ident(#(#param_names: #param_types,)*) -> ::uniffi::Handle {
                 ::uniffi::deps::trace!("calling: {}", #name);
                 let uniffi_lifted_args = (#lift_closure)();
@@ -326,7 +326,7 @@ fn ffi_buffer_scaffolding_fn(
     if has_rust_call_status {
         quote! {
             #[doc(hidden)]
-            #[no_mangle]
+            #[unsafe(no_mangle)]
             pub unsafe extern "C" fn #ident(
                 arg_ptr: *mut ::uniffi::FfiBufferElement,
                 return_ptr: *mut ::uniffi::FfiBufferElement,
@@ -348,7 +348,7 @@ fn ffi_buffer_scaffolding_fn(
     } else {
         quote! {
             #[doc(hidden)]
-            #[no_mangle]
+            #[unsafe(no_mangle)]
             pub unsafe extern "C" fn #ident(
                 arg_ptr: *mut ::uniffi::FfiBufferElement,
                 return_ptr: *mut ::uniffi::FfiBufferElement,
diff --git a/uniffi_macros/src/export/trait_interface.rs b/uniffi_macros/src/export/trait_interface.rs
index 2cc99f88d..f1b982765 100644
--- a/uniffi_macros/src/export/trait_interface.rs
+++ b/uniffi_macros/src/export/trait_interface.rs
@@ -45,7 +45,7 @@ pub(super) fn gen_trait_scaffolding(
 
     let helper_fn_tokens = quote! {
         #[doc(hidden)]
-        #[no_mangle]
+        #[unsafe(no_mangle)]
         /// Clone a pointer to this object type
         ///
         /// Safety: Only pass pointers returned by a UniFFI call.  Do not pass pointers that were
@@ -67,7 +67,7 @@ pub(super) fn gen_trait_scaffolding(
         }
 
         #[doc(hidden)]
-        #[no_mangle]
+        #[unsafe(no_mangle)]
         /// Free a pointer to this object type
         ///
         /// Safety: Only pass pointers returned by a UniFFI call.  Do not pass pointers that were
diff --git a/uniffi_macros/src/object.rs b/uniffi_macros/src/object.rs
index afc961600..c5ab8e0da 100644
--- a/uniffi_macros/src/object.rs
+++ b/uniffi_macros/src/object.rs
@@ -62,7 +62,7 @@ pub fn expand_object(input: DeriveInput, options: DeriveOptions) -> syn::Result<
 
     Ok(quote! {
         #[doc(hidden)]
-        #[no_mangle]
+        #[unsafe(no_mangle)]
         pub unsafe extern "C" fn #clone_fn_ident(
             ptr: *const ::std::ffi::c_void,
             call_status: &mut ::uniffi::RustCallStatus
@@ -75,7 +75,7 @@ pub fn expand_object(input: DeriveInput, options: DeriveOptions) -> syn::Result<
         }
 
         #[doc(hidden)]
-        #[no_mangle]
+        #[unsafe(no_mangle)]
         pub unsafe extern "C" fn #free_fn_ident(
             ptr: *const ::std::ffi::c_void,
             call_status: &mut ::uniffi::RustCallStatus
diff --git a/uniffi_macros/src/setup_scaffolding.rs b/uniffi_macros/src/setup_scaffolding.rs
index 79189b7b3..63a089fa2 100644
--- a/uniffi_macros/src/setup_scaffolding.rs
+++ b/uniffi_macros/src/setup_scaffolding.rs
@@ -39,7 +39,7 @@ pub fn setup_scaffolding(namespace: String) -> Result<TokenStream> {
 
         #[allow(clippy::missing_safety_doc, missing_docs)]
         #[doc(hidden)]
-        #[no_mangle]
+        #[unsafe(no_mangle)]
         pub extern "C" fn #ffi_contract_version_ident() -> ::std::primitive::u32 {
             #UNIFFI_CONTRACT_VERSION
         }
@@ -55,7 +55,7 @@ pub fn setup_scaffolding(namespace: String) -> Result<TokenStream> {
                 .concat_str(#namespace);
 
         #[doc(hidden)]
-        #[no_mangle]
+        #[unsafe(no_mangle)]
         pub static #namespace_static_ident: [::std::primitive::u8; #namespace_const_ident.size] =
             #namespace_const_ident.into_array();
 
@@ -65,7 +65,7 @@ pub fn setup_scaffolding(namespace: String) -> Result<TokenStream> {
 
         #[allow(clippy::missing_safety_doc, missing_docs)]
         #[doc(hidden)]
-        #[no_mangle]
+        #[unsafe(no_mangle)]
         pub extern "C" fn #ffi_rustbuffer_alloc_ident(
             size: ::std::primitive::u64,
             call_status: &mut ::uniffi::RustCallStatus,
@@ -75,7 +75,7 @@ pub fn setup_scaffolding(namespace: String) -> Result<TokenStream> {
 
         #[allow(clippy::missing_safety_doc, missing_docs)]
         #[doc(hidden)]
-        #[no_mangle]
+        #[unsafe(no_mangle)]
         pub unsafe extern "C" fn #ffi_rustbuffer_from_bytes_ident(
             bytes: ::uniffi::ForeignBytes,
             call_status: &mut ::uniffi::RustCallStatus,
@@ -85,7 +85,7 @@ pub fn setup_scaffolding(namespace: String) -> Result<TokenStream> {
 
         #[allow(clippy::missing_safety_doc, missing_docs)]
         #[doc(hidden)]
-        #[no_mangle]
+        #[unsafe(no_mangle)]
         pub unsafe extern "C" fn #ffi_rustbuffer_free_ident(
             buf: ::uniffi::RustBuffer,
             call_status: &mut ::uniffi::RustCallStatus,
@@ -95,7 +95,7 @@ pub fn setup_scaffolding(namespace: String) -> Result<TokenStream> {
 
         #[allow(clippy::missing_safety_doc, missing_docs)]
         #[doc(hidden)]
-        #[no_mangle]
+        #[unsafe(no_mangle)]
         pub unsafe extern "C" fn #ffi_rustbuffer_reserve_ident(
             buf: ::uniffi::RustBuffer,
             additional: ::std::primitive::u64,
@@ -128,7 +128,7 @@ pub fn setup_scaffolding(namespace: String) -> Result<TokenStream> {
         macro_rules! uniffi_reexport_scaffolding {
             () => {
                 #[doc(hidden)]
-                #[no_mangle]
+                #[unsafe(no_mangle)]
                 pub extern "C" fn #reexport_hack_ident() {
                     $crate::uniffi_reexport_hack()
                 }
@@ -175,21 +175,21 @@ fn rust_future_scaffolding_fns(module_path: &str) -> TokenStream {
         quote! {
             #[allow(clippy::missing_safety_doc, missing_docs)]
             #[doc(hidden)]
-            #[no_mangle]
+            #[unsafe(no_mangle)]
             pub unsafe extern "C" fn #ffi_rust_future_poll(handle: ::uniffi::Handle, callback: ::uniffi::RustFutureContinuationCallback, data: u64) {
                 ::uniffi::ffi::rust_future_poll::<#return_type, crate::UniFfiTag>(handle, callback, data);
             }
 
             #[allow(clippy::missing_safety_doc, missing_docs)]
             #[doc(hidden)]
-            #[no_mangle]
+            #[unsafe(no_mangle)]
             pub unsafe extern "C" fn #ffi_rust_future_cancel(handle: ::uniffi::Handle) {
                 ::uniffi::ffi::rust_future_cancel::<#return_type, crate::UniFfiTag>(handle)
             }
 
             #[allow(clippy::missing_safety_doc, missing_docs)]
             #[doc(hidden)]
-            #[no_mangle]
+            #[unsafe(no_mangle)]
             pub unsafe extern "C" fn #ffi_rust_future_complete(
                 handle: ::uniffi::Handle,
                 out_status: &mut ::uniffi::RustCallStatus
@@ -199,7 +199,7 @@ fn rust_future_scaffolding_fns(module_path: &str) -> TokenStream {
 
             #[allow(clippy::missing_safety_doc, missing_docs)]
             #[doc(hidden)]
-            #[no_mangle]
+            #[unsafe(no_mangle)]
             pub unsafe extern "C" fn #ffi_rust_future_free(handle: ::uniffi::Handle) {
                 ::uniffi::ffi::rust_future_free::<#return_type, crate::UniFfiTag>(handle)
             }
diff --git a/uniffi_macros/src/util.rs b/uniffi_macros/src/util.rs
index b58ddbbb0..9e6f44c5b 100644
--- a/uniffi_macros/src/util.rs
+++ b/uniffi_macros/src/util.rs
@@ -115,7 +115,7 @@ pub fn create_metadata_items(
         let ident = Ident::new(&name, Span::call_site());
         quote! {
             #[doc(hidden)]
-            #[no_mangle]
+            #[unsafe(no_mangle)]
             pub extern "C" fn #ident() -> u16 {
                 // Force constant evaluation to ensure:
                 // 1. The checksum is computed at compile time; and
@@ -128,7 +128,7 @@ pub fn create_metadata_items(
 
     quote! {
         const #const_ident: ::uniffi::MetadataBuffer = #metadata_expr;
-        #[no_mangle]
+        #[unsafe(no_mangle)]
         #[doc(hidden)]
         pub static #static_ident: [u8; #const_ident.size] = #const_ident.into_array();

Why were these places not changed as well?—I just search+replaced all #[no_mangle] with #[unsafe(no_mangle)].

@badboy
Copy link
Member

badboy commented Mar 10, 2025

Why were these places not changed as well?—I just search+replaced all #[no_mangle] with #[unsafe(no_mangle)].

We shouldn't have to, as those macros are still compiled under edition 2021 (now that we did update our MSRV we can add those though).

@bes
Copy link
Author

bes commented Mar 10, 2025

Alright fair enough, but I have no idea why it doesn't work for me without those changes (haven't researched it further than search+replace and it started working)

@mhammond
Copy link
Member

I guess that what's happening is that our templates actually emit the creation of the uniffi_reexport_scaffolding! macro here

So I guess technically it's not our macros crate which is considered here, it's actually the target crate?

@mhammond
Copy link
Member

hrm, according to #1242, this reexport hack should no longer be necessary - @bes do things work if you remove that line entirely?

@bes
Copy link
Author

bes commented Mar 10, 2025

@mhammond I think maybe you linked the wrong issue? But removing the uniffi_reexport_scaffolding! macro seems to work for me.

@mhammond
Copy link
Member

That was the correct issue but finding the thread in it isn't obvious :) So it sounds like the better fix here might be to make that macro a no-op for b/w compat purposes and to remove the docs talking about it?

@bes
Copy link
Author

bes commented Mar 10, 2025

As long as there is a release soon I'm fine with whatever! Thank you for an excellent library!

mhammond added a commit to mhammond/uniffi-rs that referenced this issue Mar 11, 2025
As noted in mozilla#2459 and mozilla#2475, the `uniffi_reexport_scaffolding!` macro doesn't
work in Rust 2024.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants