I'm writing a Rust library to facilitate implementing the following C API in Rust. That is, it should be possible to create a Rust-idiomatic implementation by depending on my wrapper library.

// Called first. Implementer may allocate memory here.
void init();

// For each input: start is called, then run is called repeatedly, finally stop
// is called. The input pointer is valid until the end of stop.
void start(const char* input, size_t size);
void run();
void stop();

// Called last. Implementer should free all allocated memory.
void deinit();

To clarify the required order of calls, the following example code calls the API as specified:

#include <stdlib.h>
#include <string.h>

#include "api.h"

void run_input(const char* s) {
  size_t size = strlen(s);
  char* data = malloc(size);
  memcpy(data, s, size);
  start(data, size);

int main(int argc, char** argv) {

Note: neither the API nor the code calling it are mine. Only the Rust wrapper code (below) is mine. The API is well established with multiple existing implementations and callers; I cannot change it.

Because the lifetime of each input spans multiple calls into Rust, it's difficult to ensure the implementation has access to it for right lifetime. I also want to support implementations which persist mutable data between different inputs. Here is my current solution:

//! A helper library for implementing the C API. The implementer should
//! implement the Runner and Factory traits:
//!     struct RunnerImpl;
//!     impl Runner for RunnerImpl {
//!         // ...
//!     }
//!     struct FactoryImpl;
//!     impl Factory for FactoryImpl {
//!         // ...
//!     }
//! and call the macro:
//!     factory!(FactoryImpl);

use std::borrow::BorrowMut;
use std::mem::transmute;
use std::slice;

pub trait Runner {
    fn run(&mut self);
    fn stop(&mut self);

pub trait Factory {
    fn default() -> Self
        Self: Sized;
    fn start_runner<'a>(&'a mut self, input: &'a [u8]) -> Box<dyn Runner + 'a>;

struct Wrapper {
    factory: Box<dyn Factory>,
    runner: Option<Box<dyn Runner>>,

impl Wrapper {
    fn new<F: Factory + 'static>() -> Self {
        Wrapper {
            factory: Box::new(F::default()),
            runner: None,

    fn runner(&mut self) -> &mut (dyn Runner + 'static) {

static mut INSTANCE: *mut Wrapper = 0 as *mut _;
unsafe fn instance() -> &'static mut Wrapper {
    assert_ne!(INSTANCE, 0 as *mut _);
    &mut *INSTANCE

pub unsafe fn init_impl<F: Factory + 'static>() {
    INSTANCE = Box::into_raw(Box::new(Wrapper::new::<F>()));

pub unsafe extern "C" fn start(input: *const libc::c_char, size: libc::size_t) {
    // The actual lifetime of input is until the stop() call. Because this spans multiple FFI calls
    // into rust code, the lifetime can't be expressed in rust. Therefore pretend it is 'static. In
    // stop() we drop Runner, preventing the reference from leaking (?).
    // The Factory reference should have the same lifetime, and again we pretend it is 'static.
    // The wrapper doesn't access factory while running, so it's safe to pretend that runner has
    // exclusive access to it.
    let input = slice::from_raw_parts(input as *const u8, size);
    let f: &mut dyn Factory = instance().factory.borrow_mut();
    let fs: &'static mut dyn Factory = transmute(f);
    instance().runner = Some(fs.start_runner(input));

pub unsafe extern "C" fn run() {

pub unsafe extern "C" fn stop() {
    instance().runner = None;

pub unsafe extern "C" fn deinit() {
    INSTANCE = 0 as *mut _;

macro_rules! factory {
    ($factory: path) => {
        pub unsafe extern "C" fn init() {

My intention is that each Runner can hold a reference to the Factory to persist data between inputs, and also hold a reference to input for use in run() and stop(), but can't leak input beyond its lifetime.

I mainly want to know whether the lifetime munging is safe. Assuming the API is called as specified, can an implementation of Runner and Factory cause use-after-free access to input? Can the transmute cause any trouble?

  • \$\begingroup\$ Can you provide an example of usage of this API? \$\endgroup\$ – PitaJ Dec 5 '19 at 21:00
  • \$\begingroup\$ Can there only be a single instance? Regardless, you should return a pointer from init and require your user to pass that pointer to start, run, stop, and deinit. \$\endgroup\$ – PitaJ Dec 5 '19 at 21:08
  • \$\begingroup\$ @PitaJ IIUC you are suggesting changes to the C API. I can't change that part, it's given. Only the Rust code is mine. Are you asking for example code calling the C API, or example code implementing the Runner and Factory traits? \$\endgroup\$ – stewbasic Dec 6 '19 at 2:25
  • \$\begingroup\$ Just to confirm: you absolutely can't modify the C API, is that correct? I was asking for an example of C API usage. \$\endgroup\$ – PitaJ Dec 6 '19 at 18:42
  • \$\begingroup\$ @PitaJ I added to the question example calling code and an explicit note that I can't change the API. btw I put the "api" tag on the question because I view the Runner and Factory traits as an API also; they specify the interface that the user of my wrapper must implement. \$\endgroup\$ – stewbasic Dec 8 '19 at 20:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.