Crate closure_ffi

Source
Expand description

Provides wrappers around closures which allows them to be called through context-free unsafe bare functions.

Context-free bare functions are not needed very often, as properly designed C APIs typically allow the user to specify an opaque pointer to a context object which will be provided to the function pointer. However, this is not always the case, and may be impossible in less common scenarios, e.g. function hooking for game modding/hacking.

§Features

The crate comes with the following feature flags:

§Stable

  • std (default): Use std features. When this is turned off, the crate is compatible with no_std, although a global allocator must be defined.
  • global_jit_alloc (default): Provides the GlobalJitAlloc ZST which defers to a global JIT allocator implementation provided either through default_jit_alloc feature or the global_jit_alloc! macro.
  • default_jit_alloc (default): Provides a global JIT allocator implementation through the jit-allocator2 crate. Note that said crate relies on operating system APIs, so while some no_std configurations are supported, bare metal ones will not be able to use this feature.
  • proc_macros: Provides the bare_hrtb proc macro which is necessary for creating bare functions with signatures that involve higher-kinded lifetimes (i.e. for<'a, ...> statements).

§Unstable (require a nightly compiler)

  • unstable: Enable the use of unstable Rust features for aspects of the crate that benefit from them without causing any API breaks. Unstable features that can cause breaking changes when enabled are gated separately, and also enable this feature.
  • tuple_trait: Adds a core::marker::Tuple bound on FnPtr::Args. This allows downstream crates to easily integrate the library with closure-related nightly features such as unboxed_closures and fn_traits.
  • c_variadic: Adds partial (no invocation through call) FnPtr and Fn*Thunk implementations for variadic functions.
  • coverage: Enables support for the -C instrument-coverage compiler flag.

§Examples

Passing a closure to a C API taking a contextless function pointer:

use closure_ffi::{BareFnMut};
// Imagine we have an foreign C API for reigstering and unregistering some callback function.
// Notably, the API does not let the user provide a context object to the callback.
unsafe extern "C" fn ffi_register_callback(cb: unsafe extern "C" fn(u32)) {
    // ...
}
unsafe extern "C" fn ffi_unregister_callback(cb: unsafe extern "C" fn(u32)) {
    // ...
}

#[cfg(feature = "default_jit_alloc")]
{
    // We want to keep track of sum of callback arguments without using 
    // statics. This is where closure-ffi comes in:
    let mut sum = 0; // Non-'static closures work too!
    let wrapped = BareFnMut::new_c(|x: u32| {
        sum += x;
    });

    // Safety: Here, we assert that the foreign API won't use the callback
    // in ways that break Rust's safety rules. Namely:
    // - The exclusivity of the FnMut's borrow is respected.
    // - If the calls are made from a different thread, the closure is Sync.
    // - We unregister the callback before the BareFnMut is dropped.
    unsafe {
        ffi_register_callback(wrapped.bare());
        // Do something that triggers the callback...
        ffi_unregister_callback(wrapped.bare());
    }

    drop(wrapped);
    println!("{sum}");
}

§Credits

  • tremwil: Library author and maintainer
  • Dasaav: lock (x14) push eax x86 byte sequence idea

Modules§

bare_closure
Provides the BareFnOnce, BareFnMut and BareFn wrapper types which allow closures to be called through context-free unsafe bare functions.
cc
Defines calling convention marker types for use with BareFn variants.
jit_alloc
Abstractions around allocators that provide dual-mapped memory with XOR protection rules (one RW view and one RX view) suitable for emitting code at runtime.
prelude
Common imports required to use closure-ffi.
traits
Traits that closure-ffi uses to power its functionality.

Macros§

bare_hrtbproc_macros
Declares a wrapper type around a higher-ranked bare function which can be used with BareFn and friends.
global_jit_allocglobal_jit_alloc and non-default_jit_alloc
Defines a global JitAlloc implementation which GlobalJitAlloc will defer to.

Structs§

BareFnAny
Wrapper around a Fn closure which exposes a bare function thunk that can invoke it without additional arguments.
BareFnMutAny
Wrapper around a FnMut closure which exposes a bare function thunk that can invoke it without additional arguments.
BareFnOnceAny
Wrapper around a FnOnce closure which exposes a bare function thunk that can invoke it without additional arguments.
JitAllocError
Anonymous error that may be returned by JitAlloc implementations when JitAlloc::alloc or JitAlloc::release fail.
UntypedBareFn
Type-erased wrapper around a Fn closure which exposes a pointer to a bare function thunk.
UntypedBareFnMut
Type-erased wrapper around a FnMut closure which exposes a pointer to a bare function thunk.
UntypedBareFnOnce
Type-erased wrapper around a FnOnce closure which exposes a pointer to a bare function thunk.

Traits§

JitAlloc
Generic allocator providing virtual memory suitable for emitting code at runtime.

Type Aliases§

BareFn
Wrapper around a Fn closure which exposes a bare function thunk that can invoke it without additional arguments.
BareFnMut
Wrapper around a FnMut closure which exposes a bare function thunk that can invoke it without additional arguments.
BareFnMutSync
Wrapper around a FnMut closure which exposes a bare function thunk that can invoke it without additional arguments.
BareFnOnce
Wrapper around a FnOnce closure which exposes a bare function thunk that can invoke it without additional arguments.
BareFnOnceSync
Wrapper around a FnOnce closure which exposes a bare function thunk that can invoke it without additional arguments.
BareFnSync
Wrapper around a Fn closure which exposes a bare function thunk that can invoke it without additional arguments.