ffi_support/
macros.rs

1/* Copyright 2018-2019 Mozilla Foundation
2 *
3 * Licensed under the Apache License (Version 2.0), or the MIT license,
4 * (the "Licenses") at your option. You may not use this file except in
5 * compliance with one of the Licenses. You may obtain copies of the
6 * Licenses at:
7 *
8 *    http://www.apache.org/licenses/LICENSE-2.0
9 *    http://opensource.org/licenses/MIT
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the Licenses is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the Licenses for the specific language governing permissions and
15 * limitations under the Licenses. */
16
17/// Implements [`IntoFfi`][crate::IntoFfi] for the provided types (more than one
18/// may be passed in) by allocating `$T` on the heap as an opaque pointer.
19///
20/// This is typically going to be used from the "Rust component", and not the
21/// "FFI component" (see the top level crate documentation for more
22/// information), however you will still need to implement a destructor in the
23/// FFI component using [`define_box_destructor!`][crate::define_box_destructor].
24///
25/// In general, is only safe to do for `send` types (even this is dodgy, but
26/// it's often necessary to keep the locking on the other side of the FFI, so
27/// Sync is too harsh), so we enforce this in this macro. (You're still free to
28/// implement this manually, if this restriction is too harsh for your use case
29/// and you're certain you know what you're doing).
30#[macro_export]
31macro_rules! implement_into_ffi_by_pointer {
32    ($($T:ty),* $(,)*) => {$(
33        unsafe impl $crate::IntoFfi for $T where $T: Send {
34            type Value = *mut $T;
35
36            #[inline]
37            fn ffi_default() -> *mut $T {
38                std::ptr::null_mut()
39            }
40
41            #[inline]
42            fn into_ffi_value(self) -> *mut $T {
43                Box::into_raw(Box::new(self))
44            }
45        }
46    )*}
47}
48
49/// Implements [`IntoFfi`][crate::IntoFfi] for the provided types (more than one
50/// may be passed in) by converting to the type to a JSON string.
51///
52/// Additionally, most of the time we recomment using this crate's protobuf
53/// support, instead of JSON.
54///
55/// This is typically going to be used from the "Rust component", and not the
56/// "FFI component" (see the top level crate documentation for more
57/// information).
58///
59/// Note: Each type passed in must implement or derive `serde::Serialize`.
60///
61/// Note: for this to works, the crate it's called in must depend on `serde` and
62/// `serde_json`.
63///
64/// ## Panics
65///
66/// The [`IntoFfi`][crate::IntoFfi] implementation this macro generates may
67/// panic in the following cases:
68///
69/// - You've passed a type that contains a Map that has non-string keys (which
70///   can't be represented in JSON).
71///
72/// - You've passed a type which has a custom serializer, and the custom
73///   serializer failed.
74///
75/// These cases are both rare enough that this still seems fine for the majority
76/// of uses.
77#[macro_export]
78macro_rules! implement_into_ffi_by_json {
79    ($($T:ty),* $(,)*) => {$(
80        unsafe impl $crate::IntoFfi for $T where $T: serde::Serialize {
81            type Value = *mut std::os::raw::c_char;
82            #[inline]
83            fn ffi_default() -> *mut std::os::raw::c_char {
84                std::ptr::null_mut()
85            }
86            #[inline]
87            fn into_ffi_value(self) -> *mut std::os::raw::c_char {
88                // This panic is inside our catch_panic, so it should be fine.
89                // We've also documented the case where the IntoFfi impl that
90                // calls this panics, and it's rare enough that it shouldn't
91                // matter that if it happens we return an ExternError
92                // representing a panic instead of one of some other type
93                // (especially given that the application isn't likely to be
94                // able to meaningfully handle JSON serialization failure).
95                let as_string = serde_json::to_string(&self).unwrap();
96                $crate::rust_string_to_c(as_string)
97            }
98        }
99    )*}
100}
101
102/// Implements [`IntoFfi`][crate::IntoFfi] for the provided types (more than one
103/// may be passed in) implementing `prost::Message` (protobuf auto-generated
104/// type) by converting to the type to a [`ByteBuffer`][crate::ByteBuffer]. This
105/// [`ByteBuffer`][crate::ByteBuffer] should later be passed by value.
106///
107/// Note: for this to works, the crate it's called in must depend on `prost`.
108///
109/// Note: Each type passed in must implement or derive `prost::Message`.
110#[macro_export]
111macro_rules! implement_into_ffi_by_protobuf {
112    ($($FFIType:ty),* $(,)*) => {$(
113        unsafe impl $crate::IntoFfi for $FFIType where $FFIType: prost::Message {
114            type Value = $crate::ByteBuffer;
115            #[inline]
116            fn ffi_default() -> Self::Value {
117                Default::default()
118            }
119
120            #[inline]
121            fn into_ffi_value(self) -> Self::Value {
122                use prost::Message;
123                let mut bytes = Vec::with_capacity(self.encoded_len());
124                // Unwrap is safe, since we have reserved sufficient capacity in
125                // the vector.
126                self.encode(&mut bytes).unwrap();
127                bytes.into()
128            }
129        }
130    )*}
131}
132
133/// Implement [`InfoFfi`][crate::IntoFfi] for a type by converting through
134/// another type.
135///
136/// The argument `$MidTy` argument must implement `From<$SrcTy>` and
137/// [`InfoFfi`][crate::IntoFfi].
138///
139/// This is provided (even though it's trivial) because it is always safe (well,
140/// so long as `$MidTy`'s [`IntoFfi`][crate::IntoFfi] implementation is
141/// correct), but would otherwise require use of `unsafe` to implement.
142#[macro_export]
143macro_rules! implement_into_ffi_by_delegation {
144    ($SrcTy:ty, $MidTy:ty) => {
145        unsafe impl $crate::IntoFfi for $SrcTy
146        where
147            $MidTy: From<$SrcTy> + $crate::IntoFfi,
148        {
149            // The <$MidTy as SomeTrait>::method is required even when it would
150            // be ambiguous due to some obscure details of macro syntax.
151            type Value = <$MidTy as $crate::IntoFfi>::Value;
152
153            #[inline]
154            fn ffi_default() -> Self::Value {
155                <$MidTy as $crate::IntoFfi>::ffi_default()
156            }
157
158            #[inline]
159            fn into_ffi_value(self) -> Self::Value {
160                use $crate::IntoFfi;
161                <$MidTy as From<$SrcTy>>::from(self).into_ffi_value()
162            }
163        }
164    };
165}
166
167/// For a number of reasons (name collisions are a big one, but, it also wouldn't work on all
168/// platforms), we cannot export `extern "C"` functions from this library. However, it's pretty
169/// common to want to free strings allocated by rust, so many libraries will need this, so we
170/// provide it as a macro.
171///
172/// It simply expands to a `#[no_mangle] pub unsafe extern "C" fn` which wraps this crate's
173/// [`destroy_c_string`][crate::destroy_c_string] function.
174///
175/// ## Caveats
176///
177/// If you're using multiple separately compiled rust libraries in your application, it's critical
178/// that you are careful to only ever free strings allocated by a Rust library using the same rust
179/// library. Passing them to a different Rust library's string destructor will cause you to corrupt
180/// multiple heaps.
181///
182/// Additionally, be sure that all strings you pass to this were actually allocated by rust. It's a
183/// common issue for JNA code to transparently convert Pointers to things to Strings behind the
184/// scenes, which is quite risky here. (To avoid this in JNA, only use `String` for passing
185/// read-only strings into Rust, e.g. it's for passing `*const c_char`. All other uses should use
186/// `Pointer` and `getString()`).
187///
188/// Finally, to avoid name collisions, it is strongly recommended that you provide an name for this
189/// function unique to your library.
190///
191/// ## Example
192///
193/// ```rust
194/// # use ffi_support::define_string_destructor;
195/// define_string_destructor!(mylib_destroy_string);
196/// ```
197#[macro_export]
198macro_rules! define_string_destructor {
199    ($mylib_destroy_string:ident) => {
200        /// Public destructor for strings managed by the other side of the FFI.
201        ///
202        /// # Safety
203        ///
204        /// This will free the string pointer it gets passed in as an argument,
205        /// and thus can be wildly unsafe if misused.
206        ///
207        /// See the documentation of `ffi_support::destroy_c_string` and
208        /// `ffi_support::define_string_destructor!` for further info.
209        #[no_mangle]
210        pub unsafe extern "C" fn $mylib_destroy_string(s: *mut std::os::raw::c_char) {
211            // Note: This should never happen, but in the case of a bug aborting
212            // here is better than the badness that happens if we unwind across
213            // the FFI boundary.
214            $crate::abort_on_panic::with_abort_on_panic(|| {
215                if !s.is_null() {
216                    $crate::destroy_c_string(s)
217                }
218            });
219        }
220    };
221}
222
223/// Define a (public) destructor for a type that was allocated by
224/// `Box::into_raw(Box::new(value))` (e.g. a pointer which is probably opaque).
225///
226/// ## Caveats
227///
228/// When called over the FFI, this can go wrong in a ridiculous number of ways,
229/// and we can't really prevent any of them. But essentially, the caller (on the
230/// other side of the FFI) needs to be extremely careful to ensure that it stops
231/// using the pointer after it's freed.
232///
233/// Also, to avoid name collisions, it is strongly recommended that you provide
234/// an name for this function unique to your library. (This is true for all
235/// functions you expose).
236///
237/// However, when called from rust, this is safe, as it becomes a function that
238/// just drops a `Option<Box<T>>` with some panic handling.
239///
240/// ## Example
241///
242/// ```rust
243/// # use ffi_support::define_box_destructor;
244/// struct CoolType(Vec<i32>);
245///
246/// define_box_destructor!(CoolType, mylib_destroy_cooltype);
247/// ```
248#[macro_export]
249macro_rules! define_box_destructor {
250    ($T:ty, $destructor_name:ident) => {
251        /// # Safety
252        /// This is equivalent to calling Box::from_raw with panic handling, and
253        /// thus inherits [`Box::from_raw`]'s safety properties. That is to say,
254        /// this function is wildly unsafe.
255        #[no_mangle]
256        pub unsafe extern "C" fn $destructor_name(v: *mut $T) {
257            // We should consider passing an error parameter in here rather than
258            // aborting, but at the moment the only case where we do this
259            // (interrupt handles) should never panic in Drop, so it's probably
260            // fine.
261            $crate::abort_on_panic::with_abort_on_panic(|| {
262                if !v.is_null() {
263                    drop(Box::from_raw(v))
264                }
265            });
266        }
267    };
268}
269
270/// Define a (public) destructor for the [`ByteBuffer`][crate::ByteBuffer] type.
271///
272/// ## Caveats
273///
274/// If you're using multiple separately compiled rust libraries in your application, it's critical
275/// that you are careful to only ever free `ByteBuffer` instances allocated by a Rust library using
276/// the same rust library. Passing them to a different Rust library's string destructor will cause
277/// you to corrupt multiple heaps.
278/// One common ByteBuffer destructor is defined per Rust library.
279///
280/// Also, to avoid name collisions, it is strongly recommended that you provide an name for this
281/// function unique to your library. (This is true for all functions you expose).
282///
283/// ## Example
284///
285/// ```rust
286/// # use ffi_support::define_bytebuffer_destructor;
287/// define_bytebuffer_destructor!(mylib_destroy_bytebuffer);
288/// ```
289#[macro_export]
290macro_rules! define_bytebuffer_destructor {
291    ($destructor_name:ident) => {
292        #[no_mangle]
293        pub extern "C" fn $destructor_name(v: $crate::ByteBuffer) {
294            // Note: This should never happen, but in the case of a bug aborting
295            // here is better than the badness that happens if we unwind across
296            // the FFI boundary.
297            $crate::abort_on_panic::with_abort_on_panic(|| v.destroy())
298        }
299    };
300}
301
302/// Define a (public) destructor for a type that lives inside a lazy_static
303/// [`ConcurrentHandleMap`][crate::ConcurrentHandleMap].
304///
305/// Note that this is actually totally safe, unlike the other
306/// `define_blah_destructor` macros.
307///
308/// A critical difference, however, is that this dtor takes an `err` out
309/// parameter to indicate failure. This difference is why the name is different
310/// as well (deleter vs destructor).
311///
312/// ## Example
313///
314/// ```rust
315/// # use lazy_static::lazy_static;
316/// # use ffi_support::{ConcurrentHandleMap, define_handle_map_deleter};
317/// struct Thing(Vec<i32>);
318/// // Somewhere...
319/// lazy_static! {
320///     static ref THING_HANDLES: ConcurrentHandleMap<Thing> = ConcurrentHandleMap::new();
321/// }
322/// define_handle_map_deleter!(THING_HANDLES, mylib_destroy_thing);
323/// ```
324#[macro_export]
325macro_rules! define_handle_map_deleter {
326    ($HANDLE_MAP_NAME:ident, $destructor_name:ident) => {
327        #[no_mangle]
328        pub extern "C" fn $destructor_name(v: u64, err: &mut $crate::ExternError) {
329            $crate::call_with_result(err, || {
330                // Force type errors here.
331                let map: &$crate::ConcurrentHandleMap<_> = &*$HANDLE_MAP_NAME;
332                map.delete_u64(v)
333            })
334        }
335    };
336}
337
338/// Force a compile error if the condition is not met. Requires a unique name
339/// for the assertion for... reasons. This is included mainly because it's a
340/// common desire for FFI code, but not for other sorts of code.
341///
342/// # Examples
343///
344/// Failing example:
345///
346/// ```compile_fail
347/// ffi_support::static_assert!(THIS_SHOULD_FAIL, false);
348/// ```
349///
350/// Passing example:
351///
352/// ```
353/// ffi_support::static_assert!(THIS_SHOULD_PASS, true);
354/// ```
355#[macro_export]
356macro_rules! static_assert {
357    ($ASSERT_NAME:ident, $test:expr) => {
358        #[allow(dead_code, nonstandard_style)]
359        const $ASSERT_NAME: [u8; 0 - (!$test as bool as usize)] =
360            [0u8; 0 - (!$test as bool as usize)];
361    };
362}