c_closures/lib.rs
1//! # Purpose
2//!
3//! This crate is for producing Rust closures that can cross an FFI boundary with no generic types.
4//! It provides support for any single argument signature, along with any return type, assuming
5//! both have valid representations in C/C++ and Rust.
6//!
7//! [Here's an example.](https://github.com/Xaeroxe/c-closures-rs/tree/master/example)
8//!
9//! # Safety concerns
10//!
11//! Creating a `Closure` by itself can not cause undefined behavior, however the resulting
12//! structure is extremely dangerous. The C/C++ code may not validate arguments
13//! passed are of the correct type, which could lead to memory corruption and
14//! segfaulting. `Closure` should never be an argument to a safe function, nor should it be
15//! a public member of any structures passed into a safe function.
16//!
17//! # Usage in C/C++
18//!
19//! To use this with a C/C++ library you'll need to include the header provided in the repo,
20//! `rust_closures.h`, then link to the assembly produced by `rust_closures.c`. If the C/C++ code
21//! is being linked into a Rust binary depending on this crate, then you don't need to worry about
22//! linking to `rust_closures.c`. Then you can accept the `Closure` type anywhere that you need to
23//! accept arbitrary Rust code.
24//!
25//! # Limitations
26//!
27//! `Closure` can currently only accept a single argument, this can be worked around by making that argument
28//! a C/C++ class/struct containing multiple fields. Additionally it is strongly recommended that all types
29//! in the closure signature have a valid representation in C/C++ and Rust. Fat pointers are a common gotcha
30//! in this respect, remember slices and string slices are not a single pointer value.
31//!
32//! This cannot be used to transfer ownership across FFI boundaries, as this crate cannot reasonably guarantee
33//! both sides are using the same memory allocator, or dispose of the types in the same way. If such transfer
34//! is required, you should copy the data into a new allocation, on the side of the FFI boundary it needs to live
35//! on. The major exception to this is types with the `Copy` marker trait, which are trivially cloned and require
36//! no disposal instructions.
37//!
38//! In order to achieve this in such a general manner this crate leans heavily on heap allocations. Arguments,
39//! and return types are treated as data of arbitrary unknown length. If such heap allocations are unacceptable
40//! for your use case, consider authoring a similar structure with specific known types and involving no indirection.
41//!
42
43#![allow(non_snake_case)]
44
45use std::{ffi::c_void, mem::size_of, process::abort, ptr::null_mut};
46
47use backtrace::Backtrace;
48use log::error;
49
50include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
51
52// Send + Sync impl for Closure intentionally omitted. It's possible to create versions of these
53// for which such an impl is correct, and it may even prove to be desirable, but this version is
54// not provably Send + Sync as the closures it wraps can capture anything.
55
56impl Closure {
57 /// Transform an FnMut Rust closure into a structure you can pass into a C/C++ library.
58 ///
59 /// This structure currently assumes it will never be called in multiple threads
60 /// simultaneously. If that guarantee cannot be upheld, then you should instead use `fn_not_mut`.
61 ///
62 /// ```
63 /// # use c_closures::Closure;
64 /// let mut y = 5;
65 /// let _f = Closure::fn_mut(move |x: &i32| {
66 /// y *= 2;
67 /// *x * 2
68 /// });
69 /// ```
70 pub fn fn_mut<Arg, Return, Function>(f: Function) -> Self
71 where
72 Arg: FromClosureArgPointer,
73 Function: FnMut(Arg) -> Return + Send + 'static,
74 {
75 Self {
76 data: Box::into_raw(Box::new(f)) as *mut c_void,
77 function: Some(f_wrapper::<Arg, Return, Function>),
78 delete_data: Some(delete_me::<Function>),
79 delete_ret: Some(delete_me::<Return>),
80 }
81 }
82
83 /// Transform an Fn Rust closure into a structure you can pass into a C/C++ library.
84 ///
85 /// This structure is safe to use in multiple threads simultaneously. If your usage is single
86 /// threaded, consider `fn_mut` instead as it permits more robust closures.
87 ///
88 /// ```
89 /// # use c_closures::Closure;
90 /// let y = 5;
91 /// let _f = Closure::fn_not_mut(move |x: &i32| {
92 /// *x * y
93 /// });
94 /// ```
95 pub fn fn_not_mut<Arg, Return, Function>(f: Function) -> Self
96 where
97 Arg: FromClosureArgPointer,
98 Function: Fn(Arg) -> Return + Send + 'static,
99 {
100 Self {
101 data: Box::into_raw(Box::new(f)) as *mut c_void,
102 function: Some(f_wrapper::<Arg, Return, Function>),
103 delete_data: Some(delete_me::<Function>),
104 delete_ret: Some(delete_me::<Return>),
105 }
106 }
107
108 /// Transform an FnOnce Rust closure into a structure you can pass into a C/C++ library.
109 ///
110 /// This structure assumes it will only ever be called once. If you attempt to call it more than once
111 /// the return value will be zeroed memory. If the return type does not consider zeroed memory to be a valid
112 /// representation, then usage of the return type in this instance may result in undefined behavior.
113 ///
114 /// ```
115 /// # use c_closures::Closure;
116 /// let values = vec![String::from("1"), String::from("2"), String::from("3")];
117 /// let _f = Closure::fn_once(move |_: ()| {
118 /// for item in &values {
119 /// println!("Item: {}", item);
120 /// }
121 /// // Probably not how this would actually be used, just to demonstrate that we can.
122 /// std::mem::drop(values);
123 /// });
124 /// ```
125 pub fn fn_once<Arg, Return, Function>(f: Function) -> Self
126 where
127 Arg: FromClosureArgPointer,
128 Function: FnOnce(Arg) -> Return + Send + 'static,
129 {
130 let mut f = Some(f);
131 Self::fn_mut(move |arg| match f.take() {
132 Some(f) => f(arg),
133 None => {
134 error!("Function marked as single-use was called more than once, the closure will not be called as that would segfault. Aborting.");
135 abort()
136 }
137 })
138 }
139
140 /// Constructs a new instance of this class that when called does nothing. It provides all
141 /// possible signatures simultaneously, excluding those with a return value, because the
142 /// `Closure` machinery will do nothing with it.
143 pub fn new_noop() -> Self {
144 Self {
145 data: null_mut(),
146 function: None,
147 delete_data: None,
148 delete_ret: None,
149 }
150 }
151
152 /// Similar to the `rebind_closure` macro, except this operates on immutable references instead.
153 pub fn rebind_closure_ref<C: ClosureMarkerTrait>(&self) -> &C {
154 // size_of here is a const fn, so this branch will be optimized out of existence.
155 if size_of::<C>() != size_of::<Self>() {
156 panic!("rebind_closure_ref external definition is not the same size as internal definition. \
157 `ClosureMarkerTrait` is probably implemented incorrectly. This also might be a bug in c-closures.")
158 } else {
159 unsafe { &*(self as *const Self as *const C) }
160 }
161 }
162
163 /// Similar to the `rebind_closure` macro, except this operates on mutable references instead.
164 pub fn rebind_closure_mut<C: ClosureMarkerTrait>(&mut self) -> &mut C {
165 // size_of here is a const fn, so this branch will be optimized out of existence.
166 if size_of::<C>() != size_of::<Self>() {
167 panic!("rebind_closure_mut external definition is not the same size as internal definition. \
168 `ClosureMarkerTrait` is probably implemented incorrectly. This also might be a bug in c-closures.")
169 } else {
170 unsafe { &mut *(self as *mut Self as *mut C) }
171 }
172 }
173}
174
175// In the unlikely event a `Closure` is released while on the Rust side, we need to dispose of it correctly.
176impl Drop for Closure {
177 fn drop(&mut self) {
178 unsafe {
179 closure_release(self);
180 }
181 }
182}
183
184unsafe extern "C" fn f_wrapper<Arg, Return, Function>(f: *mut c_void, a: *mut c_void) -> *mut c_void
185where
186 Arg: FromClosureArgPointer,
187 Function: FnMut(Arg) -> Return + Send + 'static,
188{
189 let f = &mut *(f as *mut Function);
190 let arg = if a.is_null() && size_of::<Arg>() > 0 {
191 error!(
192 "Unexpected null argument received in Closure, the closure will not be called as that would segfault.\n{:?}",
193 Backtrace::new()
194 );
195 None
196 } else {
197 Some(Arg::from_arg_ptr(a))
198 };
199
200 arg.map(|arg| Box::into_raw(Box::new(f(arg))) as *mut c_void)
201 .unwrap_or(null_mut())
202}
203
204unsafe extern "C" fn delete_me<T>(t: *mut c_void) {
205 // The box takes back ownership, and is then dropped, preventing a leak of the closure data.
206 Box::from_raw(t as *mut T);
207}
208
209/// This trait identifies instances of the `Closure` type from `rust_closures.h`. In Rust land, there will be
210/// multiple instances of this type that we need to be able to cast from one to another. This trait helps us
211/// determine which of these casts are safe. To implement this use `BindgenBuilderExt::c_closures_enhancements`
212/// from `c-closures-build` on your `bindgen::Builder`.
213pub trait ClosureMarkerTrait {}
214
215impl ClosureMarkerTrait for Closure {}
216
217/// Provides a general purpose way to deref a structure from a C void pointer. Auto implemented for `Copy` types.
218pub trait FromClosureArgPointer {
219 /// # Safety
220 ///
221 /// Incorrect implementations of this trait may lead to undefined behavior. If you're trying to read out a
222 /// pointer type, then the pointer passed to this trait is a pointer to your pointer, not the pointer itself.
223 unsafe fn from_arg_ptr(ptr: *const c_void) -> Self;
224}
225
226impl<T: Copy> FromClosureArgPointer for T {
227 unsafe fn from_arg_ptr(ptr: *const c_void) -> Self {
228 *(ptr as *const T)
229 }
230}
231
232/// Rebinds a `Closure` from this crate to a `Closure` type defined externally.
233/// If you use bindgen to make bindings to C/C++ functions accepting this `Closure` type then the bindings won't
234/// be defined in terms of `c_closures`, instead your functions will want an instance of your own `Closure` definition.
235/// This macro provides a convenient way to rebind them.
236///
237/// ```
238/// use c_closures::{Closure, rebind_closure};
239/// mod ffi {
240/// // Import of bindgen generated closure here.
241/// // i.e. include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
242/// # #[repr(C)]
243/// # pub struct Closure {
244/// # inner: [u8; std::mem::size_of::<c_closures::Closure>()],
245/// # }
246/// # impl c_closures::ClosureMarkerTrait for Closure {}
247/// }
248/// # fn main () {
249/// // elsewhere
250/// let c = rebind_closure!(ffi::Closure, Closure::fn_not_mut(|_: ()| 2 + 2));
251/// # }
252/// ```
253#[macro_export]
254macro_rules! rebind_closure {
255 ($external_name:ty, $closure:expr) => {
256 { // Additional scope added to prevent leaking of the fn definition.
257 fn is_closure_type<C: $crate::ClosureMarkerTrait>() {}
258
259 // size_of here is a const fn, so this branch will be optimized out of existence.
260 if ::std::mem::size_of::<$external_name>() != ::std::mem::size_of::<$crate::Closure>() {
261 panic!("rebind_ref! macro external definition is not the same size as internal definition. \
262 `ClosureMarkerTrait` is probably implemented incorrectly.")
263 } else {
264 is_closure_type::<$external_name>(); // Intentionally creates a compiler error if the marker trait isn't implemented.
265 unsafe {
266 ::std::mem::transmute::<$crate::Closure, $external_name>($closure)
267 }
268 }
269 }
270 };
271}
272
273#[cfg(test)]
274mod tests {
275 use std::{
276 ffi::{CStr, CString},
277 sync::Arc,
278 };
279
280 use super::*;
281
282 #[test]
283 fn fn_not_mut() {
284 let y = 4;
285 let mut closure = Closure::fn_not_mut(move |x: i32| x + x + y);
286 unsafe {
287 let ret = closure_call(&mut closure, &mut 2 as *mut i32 as _);
288 assert_eq!(<i32 as FromClosureArgPointer>::from_arg_ptr(ret), 8);
289 closure_release_return_value(&mut closure, ret);
290 closure_release(&mut closure);
291 }
292 }
293
294 #[test]
295 fn fn_mut() {
296 let mut y = 4;
297 let mut closure = Closure::fn_mut(move |x: i32| {
298 y *= 2;
299 x + x + y
300 });
301 unsafe {
302 let ret = closure_call(&mut closure, &mut 2 as *mut i32 as _);
303 assert_eq!(<i32 as FromClosureArgPointer>::from_arg_ptr(ret), 12);
304 closure_release_return_value(&mut closure, ret);
305
306 let ret = closure_call(&mut closure, &mut 2 as *mut i32 as _);
307 assert_eq!(<i32 as FromClosureArgPointer>::from_arg_ptr(ret), 20);
308 closure_release_return_value(&mut closure, ret);
309 closure_release(&mut closure);
310 }
311 }
312
313 #[test]
314 fn fn_once() {
315 let mut y = 4;
316 let mut closure = Closure::fn_once(move |x: i32| {
317 y *= 2;
318 x + x + y
319 });
320 unsafe {
321 let ret = closure_call(&mut closure, &mut 2 as *mut i32 as _);
322 assert_eq!(<i32 as FromClosureArgPointer>::from_arg_ptr(ret), 12);
323 closure_release_return_value(&mut closure, ret);
324
325 // I'd love to verify that a subsequent call aborts, but it's non-trivial
326 // to put that into a test suite. We'll address this if it ever becomes a problem
327 // that this testing isn't done.
328 closure_release(&mut closure);
329 }
330 }
331
332 #[test]
333 fn fn_cstring() {
334 let mut closure = Closure::fn_not_mut(|name: &CStr| {
335 CString::new(format!("Hello {}", name.to_str().unwrap())).unwrap()
336 });
337 let my_name = CString::new("Jacob").unwrap();
338 unsafe {
339 let ret = closure_call(&mut closure, &mut my_name.as_c_str() as *mut &CStr as _);
340 assert_eq!(
341 (&mut *(ret as *mut CString)).clone().into_string().unwrap(),
342 "Hello Jacob"
343 );
344 closure_release_return_value(&mut closure, ret);
345 closure_release(&mut closure);
346 }
347 }
348
349 #[test]
350 fn fn_drop_test() {
351 let value = Arc::new(());
352 let value_clone = value.clone();
353 let mut closure = Closure::fn_not_mut(move |_: ()| value_clone.clone());
354 unsafe {
355 let ret = closure_call(&mut closure, &mut () as *mut () as _);
356 assert_eq!(Arc::strong_count(&value), 3);
357 closure_release_return_value(&mut closure, ret);
358 assert_eq!(Arc::strong_count(&value), 2);
359 closure_release(&mut closure);
360 assert_eq!(Arc::strong_count(&value), 1);
361 }
362 }
363
364 struct NotAClosure;
365
366 impl ClosureMarkerTrait for NotAClosure {}
367
368 #[test]
369 #[should_panic]
370 fn bad_ref_usage() {
371 let c = Closure::fn_not_mut(|_: ()| ());
372 c.rebind_closure_ref::<NotAClosure>();
373 }
374
375 #[test]
376 #[should_panic]
377 fn bad_mut_usage() {
378 let mut c = Closure::fn_not_mut(|_: ()| ());
379 c.rebind_closure_mut::<NotAClosure>();
380 }
381
382 // Validates that calling this macro doesn't result in leaky definitions. Items
383 // defined in the macro should not exist outside of it.
384 #[test]
385 fn two_in_scope() {
386 rebind_closure!(Closure, Closure::new_noop());
387 rebind_closure!(Closure, Closure::new_noop());
388 }
389}