1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
//! # Purpose
//!
//! This crate is for producing Rust closures that can cross an FFI boundary with no generic types.
//! It provides support for any single argument signature, along with any return type, assuming
//! both have valid representations in C/C++ and Rust.
//!
//! [Here's an example.](https://github.com/Xaeroxe/c-closures-rs/tree/master/example)
//!
//! # Safety concerns
//!
//! Creating a `Closure` by itself can not cause undefined behavior, however the resulting
//! structure is extremely dangerous. The C/C++ code may not validate arguments
//! passed are of the correct type, which could lead to memory corruption and
//! segfaulting. `Closure` should never be an argument to a safe function, nor should it be
//! a public member of any structures passed into a safe function.
//!
//! # Usage in C/C++
//!
//! To use this with a C/C++ library you'll need to include the header provided in the repo,
//! `rust_closures.h`, then link to the assembly produced by `rust_closures.c`. If the C/C++ code
//! is being linked into a Rust binary depending on this crate, then you don't need to worry about
//! linking to `rust_closures.c`. Then you can accept the `Closure` type anywhere that you need to
//! accept arbitrary Rust code.
//!
//! # Limitations
//!
//! `Closure` can currently only accept a single argument, this can be worked around by making that argument
//! a C/C++ class/struct containing multiple fields. Additionally it is strongly recommended that all types
//! in the closure signature have a valid representation in C/C++ and Rust. Fat pointers are a common gotcha
//! in this respect, remember slices and string slices are not a single pointer value.
//!
//! This cannot be used to transfer ownership across FFI boundaries, as this crate cannot reasonably guarantee
//! both sides are using the same memory allocator, or dispose of the types in the same way. If such transfer
//! is required, you should copy the data into a new allocation, on the side of the FFI boundary it needs to live
//! on. The major exception to this is types with the `Copy` marker trait, which are trivially cloned and require
//! no disposal instructions.
//!
//! In order to achieve this in such a general manner this crate leans heavily on heap allocations. Arguments,
//! and return types are treated as data of arbitrary unknown length. If such heap allocations are unacceptable
//! for your use case, consider authoring a similar structure with specific known types and involving no indirection.
//!

#![allow(non_snake_case)]

use std::{ffi::c_void, mem::size_of, process::abort, ptr::null_mut};

use backtrace::Backtrace;
use log::error;

include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

// Send + Sync impl for Closure intentionally omitted. It's possible to create versions of these
// for which such an impl is correct, and it may even prove to be desirable, but this version is
// not provably Send + Sync as the closures it wraps can capture anything.

impl Closure {
    /// Transform an FnMut Rust closure into a structure you can pass into a C/C++ library.
    ///
    /// This structure currently assumes it will never be called in multiple threads
    /// simultaneously. If that guarantee cannot be upheld, then you should instead use `fn_not_mut`.
    ///
    /// ```
    /// # use c_closures::Closure;
    /// let mut y = 5;
    /// let _f = Closure::fn_mut(move |x: &i32| {
    ///     y *= 2;
    ///     *x * 2
    /// });
    /// ```
    pub fn fn_mut<Arg, Return, Function>(f: Function) -> Self
    where
        Arg: FromClosureArgPointer,
        Function: FnMut(Arg) -> Return + Send + 'static,
    {
        Self {
            data: Box::into_raw(Box::new(f)) as *mut c_void,
            function: Some(f_wrapper::<Arg, Return, Function>),
            delete_data: Some(delete_me::<Function>),
            delete_ret: Some(delete_me::<Return>),
        }
    }

    /// Transform an Fn Rust closure into a structure you can pass into a C/C++ library.
    ///
    /// This structure is safe to use in multiple threads simultaneously. If your usage is single
    /// threaded, consider `fn_mut` instead as it permits more robust closures.
    ///
    /// ```
    /// # use c_closures::Closure;
    /// let y = 5;
    /// let _f = Closure::fn_not_mut(move |x: &i32| {
    ///     *x * y
    /// });
    /// ```
    pub fn fn_not_mut<Arg, Return, Function>(f: Function) -> Self
    where
        Arg: FromClosureArgPointer,
        Function: Fn(Arg) -> Return + Send + 'static,
    {
        Self {
            data: Box::into_raw(Box::new(f)) as *mut c_void,
            function: Some(f_wrapper::<Arg, Return, Function>),
            delete_data: Some(delete_me::<Function>),
            delete_ret: Some(delete_me::<Return>),
        }
    }

    /// Transform an FnOnce Rust closure into a structure you can pass into a C/C++ library.
    ///
    /// This structure assumes it will only ever be called once. If you attempt to call it more than once
    /// the return value will be zeroed memory. If the return type does not consider zeroed memory to be a valid
    /// representation, then usage of the return type in this instance may result in undefined behavior.
    ///
    /// ```
    /// # use c_closures::Closure;
    /// let values = vec![String::from("1"), String::from("2"), String::from("3")];
    /// let _f = Closure::fn_once(move |_: ()| {
    ///     for item in &values {
    ///         println!("Item: {}", item);
    ///     }
    ///     // Probably not how this would actually be used, just to demonstrate that we can.
    ///     std::mem::drop(values);
    /// });
    /// ```
    pub fn fn_once<Arg, Return, Function>(f: Function) -> Self
    where
        Arg: FromClosureArgPointer,
        Function: FnOnce(Arg) -> Return + Send + 'static,
    {
        let mut f = Some(f);
        Self::fn_mut(move |arg| match f.take() {
            Some(f) => f(arg),
            None => {
                error!("Function marked as single-use was called more than once, the closure will not be called as that would segfault. Aborting.");
                abort()
            }
        })
    }

    /// Constructs a new instance of this class that when called does nothing. It provides all
    /// possible signatures simultaneously, excluding those with a return value, because the
    /// `Closure` machinery will do nothing with it.
    pub fn new_noop() -> Self {
        Self {
            data: null_mut(),
            function: None,
            delete_data: None,
            delete_ret: None,
        }
    }

    /// Similar to the `rebind_closure` macro, except this operates on immutable references instead.
    pub fn rebind_closure_ref<C: ClosureMarkerTrait>(&self) -> &C {
        // size_of here is a const fn, so this branch will be optimized out of existence.
        if size_of::<C>() != size_of::<Self>() {
            panic!("rebind_closure_ref external definition is not the same size as internal definition. \
            `ClosureMarkerTrait` is probably implemented incorrectly. This also might be a bug in c-closures.")
        } else {
            unsafe { &*(self as *const Self as *const C) }
        }
    }

    /// Similar to the `rebind_closure` macro, except this operates on mutable references instead.
    pub fn rebind_closure_mut<C: ClosureMarkerTrait>(&mut self) -> &mut C {
        // size_of here is a const fn, so this branch will be optimized out of existence.
        if size_of::<C>() != size_of::<Self>() {
            panic!("rebind_closure_mut external definition is not the same size as internal definition. \
            `ClosureMarkerTrait` is probably implemented incorrectly. This also might be a bug in c-closures.")
        } else {
            unsafe { &mut *(self as *mut Self as *mut C) }
        }
    }
}

// In the unlikely event a `Closure` is released while on the Rust side, we need to dispose of it correctly.
impl Drop for Closure {
    fn drop(&mut self) {
        unsafe {
            closure_release(self);
        }
    }
}

unsafe extern "C" fn f_wrapper<Arg, Return, Function>(f: *mut c_void, a: *mut c_void) -> *mut c_void
where
    Arg: FromClosureArgPointer,
    Function: FnMut(Arg) -> Return + Send + 'static,
{
    let f = &mut *(f as *mut Function);
    let arg = if a.is_null() && size_of::<Arg>() > 0 {
        error!(
        "Unexpected null argument received in Closure, the closure will not be called as that would segfault.\n{:?}",
        Backtrace::new()
      );
        None
    } else {
        Some(Arg::from_arg_ptr(a))
    };

    arg.map(|arg| Box::into_raw(Box::new(f(arg))) as *mut c_void)
        .unwrap_or(null_mut())
}

unsafe extern "C" fn delete_me<T>(t: *mut c_void) {
    // The box takes back ownership, and is then dropped, preventing a leak of the closure data.
    Box::from_raw(t as *mut T);
}

/// This trait identifies instances of the `Closure` type from `rust_closures.h`. In Rust land, there will be
/// multiple instances of this type that we need to be able to cast from one to another. This trait helps us
/// determine which of these casts are safe. To implement this use `BindgenBuilderExt::c_closures_enhancements`
/// from `c-closures-build` on your `bindgen::Builder`.
pub trait ClosureMarkerTrait {}

impl ClosureMarkerTrait for Closure {}

/// Provides a general purpose way to deref a structure from a C void pointer. Auto implemented for `Copy` types.
pub trait FromClosureArgPointer {
    /// # Safety
    ///
    /// Incorrect implementations of this trait may lead to undefined behavior. If you're trying to read out a
    /// pointer type, then the pointer passed to this trait is a pointer to your pointer, not the pointer itself.
    unsafe fn from_arg_ptr(ptr: *const c_void) -> Self;
}

impl<T: Copy> FromClosureArgPointer for T {
    unsafe fn from_arg_ptr(ptr: *const c_void) -> Self {
        *(ptr as *const T)
    }
}

/// Rebinds a `Closure` from this crate to a `Closure` type defined externally.
/// If you use bindgen to make bindings to C/C++ functions accepting this `Closure` type then the bindings won't
/// be defined in terms of `c_closures`, instead your functions will want an instance of your own `Closure` definition.
/// This macro provides a convenient way to rebind them.
///
/// ```
/// use c_closures::{Closure, rebind_closure};
/// mod ffi {
///     // Import of bindgen generated closure here.
///     // i.e. include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
/// # #[repr(C)]
/// # pub struct Closure {
/// #  inner: [u8; std::mem::size_of::<c_closures::Closure>()],
/// # }
/// # impl c_closures::ClosureMarkerTrait for Closure {}
/// }
/// # fn main () {
/// // elsewhere
/// let c = rebind_closure!(ffi::Closure, Closure::fn_not_mut(|_: ()| 2 + 2));
/// # }
/// ```
#[macro_export]
macro_rules! rebind_closure {
    ($external_name:ty, $closure:expr) => {
        { // Additional scope added to prevent leaking of the fn definition.
            fn is_closure_type<C: $crate::ClosureMarkerTrait>() {}

            // size_of here is a const fn, so this branch will be optimized out of existence.
            if ::std::mem::size_of::<$external_name>() != ::std::mem::size_of::<$crate::Closure>() {
                panic!("rebind_ref! macro external definition is not the same size as internal definition. \
                `ClosureMarkerTrait` is probably implemented incorrectly.")
            } else {
                is_closure_type::<$external_name>(); // Intentionally creates a compiler error if the marker trait isn't implemented.
                unsafe {
                    ::std::mem::transmute::<$crate::Closure, $external_name>($closure)
                }
            }
        }
    };
}

#[cfg(test)]
mod tests {
    use std::{
        ffi::{CStr, CString},
        sync::Arc,
    };

    use super::*;

    #[test]
    fn fn_not_mut() {
        let y = 4;
        let mut closure = Closure::fn_not_mut(move |x: i32| x + x + y);
        unsafe {
            let ret = closure_call(&mut closure, &mut 2 as *mut i32 as _);
            assert_eq!(<i32 as FromClosureArgPointer>::from_arg_ptr(ret), 8);
            closure_release_return_value(&mut closure, ret);
            closure_release(&mut closure);
        }
    }

    #[test]
    fn fn_mut() {
        let mut y = 4;
        let mut closure = Closure::fn_mut(move |x: i32| {
            y *= 2;
            x + x + y
        });
        unsafe {
            let ret = closure_call(&mut closure, &mut 2 as *mut i32 as _);
            assert_eq!(<i32 as FromClosureArgPointer>::from_arg_ptr(ret), 12);
            closure_release_return_value(&mut closure, ret);

            let ret = closure_call(&mut closure, &mut 2 as *mut i32 as _);
            assert_eq!(<i32 as FromClosureArgPointer>::from_arg_ptr(ret), 20);
            closure_release_return_value(&mut closure, ret);
            closure_release(&mut closure);
        }
    }

    #[test]
    fn fn_once() {
        let mut y = 4;
        let mut closure = Closure::fn_once(move |x: i32| {
            y *= 2;
            x + x + y
        });
        unsafe {
            let ret = closure_call(&mut closure, &mut 2 as *mut i32 as _);
            assert_eq!(<i32 as FromClosureArgPointer>::from_arg_ptr(ret), 12);
            closure_release_return_value(&mut closure, ret);

            // I'd love to verify that a subsequent call aborts, but it's non-trivial
            // to put that into a test suite. We'll address this if it ever becomes a problem
            // that this testing isn't done.
            closure_release(&mut closure);
        }
    }

    #[test]
    fn fn_cstring() {
        let mut closure = Closure::fn_not_mut(|name: &CStr| {
            CString::new(format!("Hello {}", name.to_str().unwrap())).unwrap()
        });
        let my_name = CString::new("Jacob").unwrap();
        unsafe {
            let ret = closure_call(&mut closure, &mut my_name.as_c_str() as *mut &CStr as _);
            assert_eq!(
                (&mut *(ret as *mut CString)).clone().into_string().unwrap(),
                "Hello Jacob"
            );
            closure_release_return_value(&mut closure, ret);
            closure_release(&mut closure);
        }
    }

    #[test]
    fn fn_drop_test() {
        let value = Arc::new(());
        let value_clone = value.clone();
        let mut closure = Closure::fn_not_mut(move |_: ()| value_clone.clone());
        unsafe {
            let ret = closure_call(&mut closure, &mut () as *mut () as _);
            assert_eq!(Arc::strong_count(&value), 3);
            closure_release_return_value(&mut closure, ret);
            assert_eq!(Arc::strong_count(&value), 2);
            closure_release(&mut closure);
            assert_eq!(Arc::strong_count(&value), 1);
        }
    }

    struct NotAClosure;

    impl ClosureMarkerTrait for NotAClosure {}

    #[test]
    #[should_panic]
    fn bad_ref_usage() {
        let c = Closure::fn_not_mut(|_: ()| ());
        c.rebind_closure_ref::<NotAClosure>();
    }

    #[test]
    #[should_panic]
    fn bad_mut_usage() {
        let mut c = Closure::fn_not_mut(|_: ()| ());
        c.rebind_closure_mut::<NotAClosure>();
    }

    // Validates that calling this macro doesn't result in leaky definitions. Items
    // defined in the macro should not exist outside of it.
    #[test]
    fn two_in_scope() {
        rebind_closure!(Closure, Closure::new_noop());
        rebind_closure!(Closure, Closure::new_noop());
    }
}