I am trying to create simple Rust-to-Rust plugin system using DLLs and I am mostly following this guide: https://michael-f-bryan.github.io/rust-ffi-guide/dynamic_loading.html
However after I load my .dll/.so file using libloading it works perfectly when I use the library as is, however when I put it into a struct with, it causes SIGSEGV on drop.
Plugin minimal example code:
pub trait Plugin{
fn new() -> Self where Self: Sized;
fn get_data(&self) -> Data;
}
pub struct Data {
pub string: String
}
#[derive(Debug, Clone)]
struct MyPlugin;
impl Plugin for MyPlugin {
fn new() -> Self {
MyPlugin {}
}
fn get_data(&self) -> Data {
Data { string: "Hello, world!".to_string() }
}
}
#[no_mangle]
pub extern "C" fn _create_plugin() -> *mut dyn Plugin {
Box::into_raw(Box::new(MyPlugin::new()))
}
App minimal example code:
use std::error::Error;
use libloading::{Library, Symbol};
use plugin::Plugin;
fn main() {
load().expect("Failed");
}
fn load() -> Result<(), Box<dyn Error>> {
let plugin = unsafe {
#[cfg(unix)]
let file = "target/debug/libplugin.so";
#[cfg(windows)]
let file = "target/debug/plugin.dll";
let lib = Library::new(file)?;
let constructor: Symbol<unsafe fn() -> *mut dyn Plugin> = lib.get(b"_create_plugin")?;
let plugin = Box::from_raw(constructor());
PluginWrapper::new(lib, plugin)
};
println!("{}", plugin.plugin.get_data().string);
Ok(())
}
struct PluginWrapper {
library: Library,
pub plugin: Box<dyn Plugin>
}
impl PluginWrapper {
pub fn new(library: Library, plugin: Box<dyn Plugin>) -> PluginWrapper {
PluginWrapper { library, plugin }
}
}
Causes segmentation fault, backtrace:
Program received signal SIGSEGV, Segmentation fault.
0x000055555555fb48 in core::ptr::drop_in_place<alloc::boxed::Box<dyn plugin::Plugin, alloc::alloc::Global>> () at /rustc/9d1b2106e23b1abd32fce1f17267604a5102f57a/library/core/src/ptr/mod.rs:188
188 /rustc/9d1b2106e23b1abd32fce1f17267604a5102f57a/library/core/src/ptr/mod.rs: No such file or directory.
(gdb) bt
#0 0x000055555555fb48 in core::ptr::drop_in_place<alloc::boxed::Box<dyn plugin::Plugin, alloc::alloc::Global>> ()
at /rustc/9d1b2106e23b1abd32fce1f17267604a5102f57a/library/core/src/ptr/mod.rs:188
#1 0x000055555555de54 in core::ptr::drop_in_place<app::PluginWrapper> ()
at /rustc/9d1b2106e23b1abd32fce1f17267604a5102f57a/library/core/src/ptr/mod.rs:188
#2 0x000055555555f1d2 in app::load () at app/src/main.rs:24
#3 0x000055555555ed79 in app::main () at app/src/main.rs:6
I also have bigger example, where I can reproduce the SIGSEGV on Windows, but not on Linux, however I do believe it's related and I am doing some fundamental mistake. Can someone point me in the right direction what I am doing wrong? Thank you.
Related
I'm trying to create a web service that can stream files from various sources. I want to declare a Source trait that each source must implement with methods for listing, reading and eventually writing files but I have a hard time finding the right pattern.
In the code below I get problems with Source not being "object safe" due to the generic parameter R.
What would be a good pattern to use to have multiple source types some local, some remote/network ones implement the same Source trait to read/write/list files?
use std::collections::HashMap;
use anyhow::{anyhow, Result};
use async_std::path::PathBuf;
use async_trait::async_trait;
use tokio::{io::{BufReader, AsyncRead}, fs::File};
#[async_trait]
pub trait Source {
// async fn list(&self, path: PathBuf, path_prefix: PathBuf) -> Result<Vec<FileMeta>>;
async fn reader<R: AsyncRead>(&self, path: PathBuf) -> Result<BufReader<R>>;
// async fn writer<W: AsyncWrite>(&self, path: PathBuf) -> Result<BufWriter<W>>;
}
#[derive(Clone)]
pub struct Local {
root: PathBuf
}
impl Local {
pub async fn new(root: PathBuf) -> Result<Self> {
Ok(Self { root: root.canonicalize().await? })
}
fn root(&self) -> PathBuf {
self.root.clone()
}
async fn resolve(&self, path: PathBuf) -> Result<PathBuf> {
let path = path.strip_prefix("/").unwrap_or(&path);
let mut result = self.root();
result.push(path);
result.canonicalize().await?;
if !result.starts_with(self.root()) {
return Err(anyhow!("Requested path is outside source root"));
}
Ok(result)
}
}
#[async_trait]
impl Source for Local {
async fn reader<R: AsyncRead>(&self, path: PathBuf) -> Result<BufReader<R>> {
let file = File::open(self.resolve(path).await?).await?;
let reader = BufReader::new(file);
Ok(reader)
}
/*
async fn writer<W: AsyncWrite>(&self, path: PathBuf) -> Result<BufWriter<W>> {
todo!()
}
*/
}
/*
The idea is to allow other file sources, HTTP, SSH, S3 ect. as long as they implement
the Source trait
#[derive(Clone)]
pub struct RemoteHTTP {
server_url: String
}
#[async_trait]
impl Source for RemoteHTTP {
async fn reader<R: AsyncRead>(&self, path: PathBuf) -> Result<BufReader<R>> {
todo!()
}
async fn writer<W: AsyncWrite>(&self, path: PathBuf) -> Result<BufWriter<W>> {
todo!()
}
}
*/
pub struct Config {
sources: HashMap<String, Box<dyn Source>>,
}
impl Config {
pub async fn load() -> Result<Self> {
let local = Local::new("/tmp/".into()).await?;
// let remote = RemoteHTTP::new("https://example.org".into());
let mut sources: HashMap<String, Box<dyn Source>> = HashMap::new();
sources.insert("local".into(), Box::new(local));
// sources.insert("remote".into(), Box::new(remote));
Ok(Self { sources })
}
pub fn sources(&self) -> HashMap<String, Box<dyn Source>> {
self.sources.clone()
}
}
#[tokio::main]
async fn main() -> Result<()> {
let config = Config::load().await;
// Store various sources into a config map
let local = Local::new("/tmp".into()).await?;
config.sources.insert("local".into(), Box::new(local));
// Create a read stream from one of hhe sources
if let Some(source) = config.sources.get("local".into()) {
let reader = source.reader("a-file".into()).await?;
// stream data with an actix HTTP service using: HttpResponse::Ok().streaming(reader)
}
Ok(())
}
You cannot use generics in methods of traits that are intended to be used dynamically. But even if you could, the signature of Source::reader() wouldn't work because it'd allow the caller to choose which reader type to return, whereas the implementation would surely want to return a concrete type. Thus every concrete implementation would fail to compile with "returned <some concrete type>, generic type R expected". The correct return type would be something like BufReader<impl AsyncRead>, but that wouldn't work because impl in return position is not yet allowed in traits, and because you need your trait to be object-safe.
Instead, Source::reader() should return a boxed AsyncRead. For example:
#[async_trait]
pub trait Source {
async fn reader(&self, path: PathBuf) -> Result<BufReader<Box<dyn AsyncRead + Unpin>>>;
}
The implementation then looks like this:
#[async_trait]
impl Source for Local {
async fn reader(&self, path: PathBuf) -> Result<BufReader<Box<dyn AsyncRead + Unpin>>> {
let file = File::open(self.resolve(path).await?).await?;
let reader = BufReader::new(Box::new(file) as _);
Ok(reader)
}
}
Your example fixed up to compile on the playground.
I've got a project that builds for ios, android and wasm targets, when I build for ios and android everything works but when I build for wasm I get the following error;
Im unsure what this error message actually means, I'm using an external crate libc, here's the code from my src/string.rs file
use libc::size_t;
// Helper struct that is used to give strings to C.
#[repr(C)]
pub struct StringPtr {
pub ptr: *const u8,
pub len: size_t,
}
impl<'a> From<&'a str> for StringPtr {
fn from(s: &'a str) -> Self {
StringPtr {
ptr: s.as_ptr(),
len: s.len() as size_t,
}
}
}
impl StringPtr {
pub fn as_str(&self) -> &str {
use std::{slice, str};
unsafe {
let slice = slice::from_raw_parts(self.ptr, self.len);
str::from_utf8(slice).unwrap()
}
}
}
and inside my lib.rs file I've got the following to import my string.rs file
extern crate libc;
mod string;
use string::StringPtr;
It's also worth noting that I am using cfg to conditionally include different code for different targets, maybe this is part of the problem?
I have a builder pattern implemented for my struct:
pub struct Struct {
pub grand_finals_modifier: bool,
}
impl Struct {
pub fn new() -> Struct {
Struct {
grand_finals_modifier: false,
}
}
pub fn grand_finals_modifier<'a>(&'a mut self, name: bool) -> &'a mut Struct {
self.grand_finals_modifier = grand_finals_modifier;
self
}
}
Is it possible in Rust to make a macro for methods like this to generalize and avoid a lot of duplicating code? Something that we can use as the following:
impl Struct {
builder_field!(hello, bool);
}
After reading the documentation, I've come up with this code:
macro_rules! builder_field {
($field:ident, $field_type:ty) => {
pub fn $field<'a>(&'a mut self,
$field: $field_type) -> &'a mut Self {
self.$field = $field;
self
}
};
}
struct Struct {
pub hello: bool,
}
impl Struct {
builder_field!(hello, bool);
}
fn main() {
let mut s = Struct {
hello: false,
};
s.hello(true);
println!("Struct hello is: {}", s.hello);
}
It does exactly what I need: creates a public builder method with specified name, specified member and type.
To complement the already accepted answer, since it is 4 years old by now, you should check out the crate rust-derive-builder. It uses procedural macros to automatically implement the builder pattern for any struct.
I am trying to make some kind of ffi to a library written in C, but got stuck. Here is a test case:
extern crate libc;
use libc::{c_void, size_t};
// this is C library api call
unsafe fn some_external_proc(_handler: *mut c_void, value: *const c_void,
value_len: size_t) {
println!("received: {:?}" , std::slice::from_raw_buf(
&(value as *const u8), value_len as usize));
}
// this is Rust wrapper for C library api
pub trait MemoryArea {
fn get_memory_area(&self) -> (*const u8, usize);
}
impl MemoryArea for u64 {
fn get_memory_area(&self) -> (*const u8, usize) {
(unsafe { std::mem::transmute(self) }, std::mem::size_of_val(self))
}
}
impl <'a> MemoryArea for &'a str {
fn get_memory_area(&self) -> (*const u8, usize) {
let bytes = self.as_bytes();
(bytes.as_ptr(), bytes.len())
}
}
#[allow(missing_copy_implementations)]
pub struct Handler<T> {
obj: *mut c_void,
}
impl <T> Handler<T> {
pub fn new() -> Handler<T> { Handler{obj: std::ptr::null_mut(),} }
pub fn invoke_external_proc(&mut self, value: T) where T: MemoryArea {
let (area, area_len) = value.get_memory_area();
unsafe {
some_external_proc(self.obj, area as *const c_void,
area_len as size_t)
};
}
}
// this is Rust wrapper user code
fn main() {
let mut handler_u64 = Handler::new();
let mut handler_str = Handler::new();
handler_u64.invoke_external_proc(1u64); // OK
handler_str.invoke_external_proc("Hello"); // also OK
loop {
match std::io::stdin().read_line() {
Ok(line) => {
let key =
line.trim_right_matches(|&: c: char| c.is_whitespace());
//// error: `line` does not live long enough
// handler_str.invoke_external_proc(key)
}
Err(std::io::IoError { kind: std::io::EndOfFile, .. }) => break ,
Err(error) => panic!("io error: {}" , error),
}
}
}
Rust playpen
I get "line does not live long enough" error if I uncomment line inside the loop. In fact, I realize that Rust is afraid that I could store short-living reference to a slice somewhere inside Handler object, but I quite sure that I wouldn't, and I also know, that it is safe to pass pointers to the external proc (actually, memory is immidiately copied at the C library side).
Is there any way for me to bypass this check?
The problem is that you are incorrectly parameterizing your struct, when you really want to do it for the function. When you create your current Handler, the struct will be specialized with a type that includes a lifetime. However, the lifetime of line is only for the block, so there can be no lifetime for Handler that lasts multiple loop iterations.
What you want is for the lifetime to be tied to the function call, not the life of the struct. As you noted, if you put the lifetime on the struct, then the struct is able to store references of that length. You don't need that, so put the generic type on the function instead:
impl Handler {
pub fn new() -> Handler { Handler{obj: std::ptr::null_mut(),} }
pub fn invoke_external_proc<T>(&mut self, value: T) where T: MemoryArea {
let (area, area_len) = value.get_memory_area();
unsafe {
some_external_proc(self.obj, area as *const c_void,
area_len as size_t)
};
}
}
Amended answer
Since you want to specialize the struct on a type, but don't care too much about the lifetime of the type, let's try this:
#[allow(missing_copy_implementations)]
pub struct Handler<T: ?Sized> {
obj: *mut c_void,
}
impl<T: ?Sized> Handler<T> {
pub fn new() -> Handler<T> { Handler{ obj: std::ptr::null_mut() } }
pub fn invoke_external_proc(&mut self, value: &T) where T: MemoryArea {
let (area, area_len) = value.get_memory_area();
unsafe {
some_external_proc(self.obj, area as *const c_void,
area_len as size_t)
};
}
}
Here, we allow the type to be unsized. Since you can't pass an unsized value as a parameter, we now have to take a reference instead. We also have to change the impl:
impl MemoryArea for str {
fn get_memory_area(&self) -> (*const u8, usize) {
let bytes = self.as_bytes();
(bytes.as_ptr(), bytes.len())
}
}
When I implement a trait on a struct in Rust it's causing the struct type not to be found. First, the working code:
trait SomeTrait {
fn new() -> Box<SomeTrait>;
fn get_some_value(&self) -> int;
}
struct SomeStruct {
value: int
}
impl SomeStruct {
fn new() -> Box<SomeStruct> {
return box SomeStruct { value: 3 };
}
fn get_some_value(&self) -> int {
return self.value;
}
}
fn main() {
let obj = SomeStruct::new();
println!("{}", obj.get_some_value());
}
Here the SomeTrait trait isn't being used. Everything works. If I now change the impl of SomeStruct to implement SomeTrait:
trait SomeTrait {
fn new() -> Box<SomeTrait>;
fn get_some_value(&self) -> int;
}
struct SomeStruct {
value: int
}
impl SomeTrait for SomeStruct {
fn new() -> Box<SomeTrait> {
return box SomeStruct { value: 3 };
}
fn get_some_value(&self) -> int {
return self.value;
}
}
fn main() {
let obj = SomeStruct::new();
println!("{}", obj.get_some_value());
}
I get the error:
trait.rs:21:13: 21:28 error: failed to resolve. Use of undeclared module `SomeStruct`
trait.rs:21 let obj = SomeStruct::new();
^~~~~~~~~~~~~~~
trait.rs:21:13: 21:28 error: unresolved name `SomeStruct::new`.
trait.rs:21 let obj = SomeStruct::new();
What am I doing wrong? Why is SomeStruct suddenly missing? Thanks!
At the moment, associated functions (non-method functions) in traits are called via the trait, i.e. SomeTrait::new(). However, if you just write this, the compiler cannot work out which impl you're using, as there's no way to specify the SomeStruct information (it only works if the special Self type is mentioned in the signature somewhere). That is, the compiler needs to be able to work out which version of new should be called. (And this is required; they could have very different behaviour:
struct Foo;
impl SomeTrait for Foo {
fn new() -> Box<SomeTrait> { box Foo as Box<SomeTrait> }
}
struct Bar;
impl SomeTrait for Bar {
fn new() -> Box<SomeTrait> {
println!("hello")
box Bar as Box<SomeTrait>
}
}
Or something more dramatic than just printing.)
This is a language hole that will be filled by UFCS. For the moment, you need to use the dummy-Self trick:
trait SomeTrait {
fn new(_dummy: Option<Self>) -> Box<SomeTrait>;
...
}
which is then called like SomeTrait::new(None::<SomeStruct>).
However, I question why you are returning a boxed object from a constructor. This is rarely a good idea, it's normally better to just return the plain type directly, and the user can box it if necessary, that is,
trait SomeTrait {
fn new() -> Self;
...
}
(NB. this signature mentions Self and thus the Option trick above isn't required.)
Sidenote: the error message is rather bad, but it just reflects how these methods are implemented; an associated function in an impl Foo is very similar to writing mod Foo { fn ... }. You can see it differ by forcing the compiler to create that module:
struct Foo;
impl Foo {
fn bar() {}
}
fn main() {
Foo::baz();
}
prints just
<anon>:7:5: 7:13 error: unresolved name `Foo::baz`.
<anon>:7 Foo::baz();
^~~~~~~~
i.e. the Foo "module" exists.