Heap argument in dynamic_lib


#1

Hello,

I’m discovering the dynamic library in Rust, and I have a question : is it possible to give a variable on the heap to a dynamic library? Because I can use the argument, but Rust fails for dropping the argument.

Example :
the dynamic library :

#[no_mangle] pub fn new(input: Box<isize>) {
    println!("input : {}", input);
    println!("before drop");
    drop(input);
    println!("after drop");
}

The caller :

#![feature(dynamic_lib)]

use std::path::Path;
use std::dynamic_lib::DynamicLibrary;
use std::mem::transmute;

fn main() {
    let path = Path::new("./libdisplay.so");
    let dyn = DynamicLibrary::open( Some(&path) ).ok().expect("display not found"); 
    let display: fn(Box<isize>) = unsafe {
        let x = dyn.symbol::<isize>("new").ok().expect("new not found");
        transmute(x)
    };
    display(Box::new(42));
}

I have as result :

$ cargo run
     Running `target/debug/fvm`
input : 42
before drop
An unknown error occurred

If I use a borrow, it works. But in my real library, I have String as argument.
I don’t know if it is normal for dynamic library or if it is a bug?

If someone had an idea, it could help me a lot!

Best regards,
Denis


#2

There’s no guarantee that the libraries are using the same allocator, and it seems that they are not. Essentially, you have to guarantee that data is allocated/deallocated by the “library” which allocates it: things created by the main binary need to be passed back to it to be dropped, things created in the dynamic library need to be passed back to that to be dropped.


#3

Thank you for you response!

But it raises another question for me : is it possible to do dynamic linking between Rust library? So, it seems that for exporting the library, we lose the Rust information (with no_mangle).

We’re creating a plugin system, and it’ll be harder if we can’t use heap variables. Is there a simpler way than using dynamic_lib?

Thank you in advance,
Denis


#4

Rust’s ABI is unspecified and unstable so you have to limit yourself to extern "C" functions and repr(C) types in any case. This doesn’t prohibit using heap allocation. It just has to be handled manually around the boundary like in C (but you probably can create safe wrappers to handle that).


#6

Seems like this is a good example: https://medium.com/jim-fleming/complex-types-with-rust-s-ffi-315d14619479


#7

Some corrections to that article:

  • don’t transmute the Box, in a few minutes from_raw/into_raw are hitting the stable channel;
  • don’t forget repr(C):
#[repr(C)]
pub struct Args {
    pub init: u32,
    pub by: u32,
}