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?
Related
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.
So I don't have a lot of knowledge on this script, compiling as part of a larger project for ARM. This comes from the zksync library which is designed primarily for x86.
I keep running into a conversion error when compiling:
7 | .try_into()
| ^^^^^^^^ the trait `std::convert::From<std::vec::Vec<u8>>` is not implemented for `[u8; 16]`
I tried using try_from() as many of my searches recommended but wasn't able to get it running, as I am still very new to rust, but open to if anyone can get it working.
I am compiling with the following target and linker below -
target - arm-unknown-linux-musleabi
linker - arm-linux-gnueabihf-ld
If anyone can recommend how to to fix this I'd love to hear, I was thinking usize instead of the u64 vars, but couldn't quite figure out if that is the rabbit hole I should try going down.
Full code:
use serde::{Deserialize, Serialize};
use std::convert::TryInto;
/// Defines time range `[valid_from, valid_until]` for which transaction is valid,
/// time format is the same as Ethereum (UNIX timestamp in seconds)
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TimeRange {
pub valid_from: u64,
pub valid_until: u64,
}
impl TimeRange {
pub fn new(valid_from: u64, valid_until: u64) -> Self {
Self {
valid_from,
valid_until,
}
}
pub fn to_be_bytes(&self) -> [u8; 16] {
[
self.valid_from.to_be_bytes(),
self.valid_until.to_be_bytes(),
]
.concat()
.try_into()
.expect("valid_from and valid_until should be u64")
}
pub fn check_correctness(&self) -> bool {
self.valid_from <= self.valid_until
}
pub fn is_valid(&self, block_timestamp: u64) -> bool {
self.valid_from <= block_timestamp && block_timestamp <= self.valid_until
}
}
impl Default for TimeRange {
fn default() -> Self {
Self {
valid_from: 0,
valid_until: u64::max_value(),
}
}
}
Your code compiles successfully on the current stable release (v1.51).
However, TryFrom<Vec<_>> for slices (which is what allows you to use try_into()) was only added in rust 1.48, so maybe you are running a rust version older that 1.48. If so, updating to 1.48+ should fix your problem.
#![feature(rustc_private)]
extern crate rustc;
use rustc::hir::intravisit as hir_visit;
use rustc::hir;
use std::marker::PhantomData;
// ----------------------------------------------------------------------------
// Why does this compile?
// ----------------------------------------------------------------------------
pub struct Map<'a> {
pub _m: PhantomData<&'a ()>,
}
pub struct SomeVisitor<'a, 'tcx: 'a> {
pub map: &'a Map<'tcx>,
}
pub enum NestedVisitorMap<'this, 'tcx: 'this> {
None,
OnlyBodies(&'this Map<'tcx>),
All(&'this Map<'tcx>),
}
pub trait Visitor<'v>: Sized {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v>;
}
impl<'v, 'tcx> Visitor<'v> for SomeVisitor<'v, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
NestedVisitorMap::All(self.map)
}
}
// ----------------------------------------------------------------------------
// Why does this *not* compile?
// ----------------------------------------------------------------------------
pub struct SomeVisitor2<'a, 'tcx: 'a> {
pub map: &'a hir::map::Map<'tcx>,
}
impl<'v, 'tcx> hir_visit::Visitor<'v> for SomeVisitor2<'v, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> hir_visit::NestedVisitorMap<'this, 'v> {
hir_visit::NestedVisitorMap::All(self.map)
}
}
fn main() {}
playground
NestedVisitorMap and Visitor
I recently ran into a lifetime issue and I decided to recreate it without any dependencies. The odd thing is that I can not recreate the lifetime error. To me both implementations look the same from the outside, but only one compiles successfully. Why is that?
rustc 1.21.0-nightly (e26688824 2017-08-27)
Update:
The problem seems to be the RefCell inside Map.
#[derive(Clone)]
pub struct Map<'hir> {
inlined_bodies: RefCell<rustc::util::nodemap::DefIdMap<&'hir hir::Body>>,
}
If there is a RefCell with a inner lifetime, it will trigger an error.
playground
Update2:
It turns out that I just mixed up lifetime subtyping. playground
I still don't know why only RefCell causes the error.
The situation is (severely simplified) this (playpen):
mod tokentree {
pub struct TokenTree;
mod serialize {
use std::collections::BTreeMap;
use super::TokenTree;
#[derive(Debug)]
pub struct InternStr;
pub trait InternStrsExt {
fn intern_strs(&self) -> BTreeMap<&str, InternStr>;
}
impl InternStrsExt for [TokenTree] {
fn intern_strs(&self) -> BTreeMap<&str, InternStr> { BTreeMap::new() }
}
}
pub use self::serialize::{InternStrsExt, InternStr};
}
use tokentree::*;
fn main() {
println!("{:?}", [TokenTree].intern_strs());
}
I get the following error (both on nightly and beta):
<anon>:20:22: 20:47 error: source trait is inaccessible
<anon>:20 println!("{:?}", [TokenTree].intern_strs());
^~~~~~~~~~~~~~~~~~~~~~~~~
My problem is that I don't even know what this is supposed to mean.
It needs a pub declaration. Also your declarations are all over the place. Recommended form is to stick your pub mod declarations first, then, use.
Here is the working example.
mod tokentree {
pub struct TokenTree;
pub mod serialize {
use std::collections::BTreeMap;
use super::TokenTree;
#[derive(Debug)]
pub struct InternStr;
pub trait InternStrsExt {
fn intern_strs(&self) -> BTreeMap<&str, InternStr>;
}
impl InternStrsExt for [TokenTree] {
fn intern_strs(&self) -> BTreeMap<&str, InternStr> { BTreeMap::new() }
}
}
pub use self::serialize::{InternStrsExt, InternStr};
}
pub use tokentree::*;
fn main() {
println!("{:?}", [TokenTree].intern_strs());
}
(playpen)
What happened here is that you stumbled upon following glitches:
https://github.com/rust-lang/rust/issues/18241
https://github.com/rust-lang/rust/issues/16264
You can't export your traits from a private module. That's why you need to change mod serialize into pub mod serialize. For example this playpen example demonstrates that exporting struct Export works, but un-commenting the println! will make it stop compiling, because we used a trait.
Tip: One thing that helps me with the visibility rules is to generate doc files and see which doc files are visible.
Previously when the code-base was in C++, I had C++ wrapper files which would link to the code base and I would run swig (version 3 for C++11 support) to generate the interface files for the target language (Python, JavaScript, C#, etc.). Then of course get all these files and libraries compiled into a shared object and have it invoked from the required languages. Now the code base is being changed to rust. So for swig to work I have the following:
Main rust code file compiling into an rlib.
Rust wrapper file that calls into the main code base but uses no_mangle and extern syntax for FFI and compiles into a staticlib.
A C file that calls the rust wrapper and is a replica of it.
Now I use swig on the C file, get the interface file for the target language, combine all the files (steps two and three) and the SWIG interface file) into a shared object and call from the target language.
So:
Is the approach fine?
I can get free functions to work. However I'm confused on how to get member functions (methods) to work. In C++ the first parameter of the member functions is the implicit this pointer. So I could return a void* handle to the class or struct to the C interface which would pass it on to others who wanted to store it (e.g. jsctypes for Firefox) and then on receiving again reinterpret_cast it to the concrete/actual type and invoke the member function on it. How do I do this with Rust?
e.g., for
pub struct A { id: SomeType, }
impl A {
pub fn some_funct_0(&mut self) {}
pub fn some_funct_1(&self) {}
}
impl SomeTrait for A {
fn some_trait_funct(&mut self) {}
}
So how do I access these member functions on an object of A (should be unmanaged and on the heap I guess?) from target languages (Python, C, etc.) or even simply a C interface?
Well, methods are just regular functions, and as Chris said, self argument has implicit connection with Self type. With your example (slightly modified) using functions from C code should be straightforward:
#[repr(C)]
pub struct A { id: u32, }
#[no_mangle]
pub extern fn new_a(id: u32) -> A {
A { id: id }
}
impl A {
#[no_mangle]
pub extern fn some_funct(&self) {
println!("Called some_funct: {}", self.id);
}
}
trait SomeTrait {
extern fn some_trait_funct(&self);
}
impl SomeTrait for A {
#[no_mangle]
extern fn some_trait_funct(&self) {
println!("Called some_trait_funct: {}", self.id);
}
}
Note that I added extern to change calling convention and #[no_mangle] to avoid name mangling and #[repr(C)] on the struct. The latter is not necessary if your code creates Boxes of the struct and pass them to C as raw pointers. I'm not sure, however, how #[no_mangle] could affect trait methods if there is more than one trait implementor - if both have #[no_mangle], there is bound to be some kind of name conflict.
Now using this type and its functions from C is easy:
#include <stdint.h>
struct A {
uint32_t id;
};
extern struct A new_a(uint32_t id);
extern void some_funct(const struct A *self);
extern void some_trait_funct(const struct A *self);
int main() {
struct A a = new_a(123);
some_funct(&a);
some_trait_funct(&a);
}
This program compiles and works:
% rustc --crate-type=staticlib test.rs
multirust: a new version of 'nightly' is available. run `multirust update nightly` to install it
note: link against the following native artifacts when linking against this static library
note: the order and any duplication can be significant on some platforms, and so may need to be preserved
note: library: System
note: library: pthread
note: library: c
note: library: m
% gcc -o test_use test_use.c libtest.a -lSystem -lpthread -lc -lm
% ./test_use
Called some_funct: 123
Called some_trait_funct: 123
If methods accepted &mut self:
#[no_mangle]
extern fn some_funct_mut(&mut self) { ... }
you would need to omit const:
extern void some_funct_mut(struct A *self);
If methods accepted self:
#[no_mangle]
extern fn some_funct_value(self) { ... }
you would need to pass the structure by value:
extern void some_funct_value(struct A self);
Though if you use the structure through an opaque pointer, calling functions taking it by value may be difficult as C has to know the exact size of the structure. Not that it is that common with opaque pointers, I believe.
Ok, as i commented in the accepted answer that I couldn't use that approach, I ended up doing something like this for other's to comment on:
The backend rust code that gets compiled to rlib:
pub trait TestTrait {
fn trait_func(&mut self) -> i32;
}
pub struct TestStruct {
value: i32,
}
impl TestStruct {
pub fn new(value: i32) -> TestStruct {
TestStruct {
value: value,
}
}
pub fn decrement(&mut self, delta: i32) {
self.value -= delta;
}
}
impl TestTrait for TestStruct {
fn trait_func(&mut self) -> i32 {
self.value += 3;
self.value
}
}
The rust-wrapper over this that links to the above rlib and compiles into staticlib (ie., .a in Linux etc):
#[no_mangle]
pub extern fn free_function_wrapper(value: i32) -> i32 {
rustlib::free_function(value)
}
#[no_mangle]
pub extern fn new_test_struct_wrapper(value: i32) -> *mut libc::c_void {
let obj = rustlib::TestStruct::new(value);
unsafe {
let raw_ptr = libc::malloc(mem::size_of::<rustlib::TestStruct>() as libc::size_t) as *mut rustlib::TestStruct;
ptr::write(&mut *raw_ptr, obj);
raw_ptr as *mut libc::c_void
}
}
#[no_mangle]
pub extern fn test_struct_decrement_wrapper(raw_ptr: *mut libc::c_void, delta: i32) {
unsafe {
mem::transmute::<*mut libc::c_void, &mut rustlib::TestStruct>(raw_ptr).decrement(delta);
}
}
#[no_mangle]
pub extern fn test_struct_trait_function_wrapper(raw_ptr: *mut libc::c_void) -> i32 {
unsafe {
mem::transmute::<*mut libc::c_void, &mut rustlib::TestStruct>(raw_ptr).trait_func()
}
}
The C-wrapper (api.h & api.c) that links to the staticlib above and compiles into a shared object if required:
extern int32_t free_function_wrapper(int32_t value);
extern void* new_test_struct_wrapper(int32_t value);
extern void test_struct_decrement_wrapper(void* ptr, int32_t delta);
extern int32_t test_struct_trait_function_wrapper(void* ptr);
int32_t free_function(int32_t value) {
return free_function_wrapper(value);
}
void* new_test_struct(int32_t value) {
return new_test_struct_wrapper(value);
}
void test_struct_decrement(void* ptr, int32_t value) {
test_struct_decrement_wrapper(ptr, value);
}
int32_t test_struct_trait_function(void* ptr) {
return test_struct_trait_function_wrapper(ptr);
}
Now just run SWIG over the C file (i've posted just the .c file - you can guess the .h over which SWIG will run) for the target language, get an interface_wrap.c generated (default name) by it and compile these source code link, them against the staticlib to get a shared-object.
Eg, for python:
swig -python interface.i
gcc -std=c99 -c -fPIC -Wall -Werror -O2 api.c interface_wrap.c -I/usr/include/python2.7
gcc -shared -o _port_sample.so api.o interface_wrap.o -L./ -lrust_wrapper
Now just call from Python and the whole thing works:
$ python
Python 2.7.6 (default, Mar 22 2014, 22:59:56)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import port_sample
>>> handle = port_sample.new_test_struct(36)
>>> port_sample.test_struct_decrement(handle, 12)
>>> value = port_sample.test_struct_trait_function(handle)
>>> print value
27
>>> exit()
I hope someone finds this useful and/or can suggest improvements etc. I've also got this thing working and committed to my github repo: https://github.com/ustulation/rust-ffi/tree/master/python-swig-rust