I'm working on a project that uses libcore and no_std, this requires an implementation of various memory manipulation functions. However, when I try to implement memcpy,
#[no_mangle]
#[no_stack_check]
pub unsafe extern fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8{
for i in 0..n {
*dest.offset(i as isize) = *src.offset(i as isize);
}
return dest;
}
I get
error: expected ident, found `*`
*dest.offset(i as isize) = *src.offset(i as isize);
^
Related
I have a Rust library that returns Vecs of size that cannot be predicted by the caller, and I'm looking for an elegant way to implement the FFI interface.
Since Vecs can't be passed over FFI, I understand I need to first return the length, and then fill a buffer with the contents.
Here's my current solution, which works by manually managing memory of the Vec and trusting the caller to
Compute the FfiVec
Create a buffer of appropriate size to copy into
Copy from the FfiVec, cleaning it up in the process
#[repr(C)]
pub struct FfiVec<T: Sized> {
ptr: *mut Vec<T>,
len: c_uint, // necessary for C process to know length of Rust Vec
}
impl<T: Sized> FfiVec<T> {
pub fn from_vec(v: Vec<T>) -> Self {
let len = v.len() as c_uint;
FfiVec {
ptr: Box::into_raw(Box::new(v)),
len,
}
}
pub fn drop(self) {
unsafe {
std::ptr::drop_in_place(self.ptr);
std::alloc::dealloc(self.ptr as *mut u8, Layout::new::<Vec<T>>())
}
}
}
#[no_mangle]
pub extern compute_my_vec() -> FfiVec<u8> {...}
#[no_mangle]
pub extern copy_from_my_vec(ffi_vec: FfiVec<u8>, buffer: *mut u8) -> {
let len = c_vec.len as usize;
let buffer_slice = unsafe { std::slice::from_raw_parts_mut(buffer, len) };
for (i, &item) in c_vec.slice().iter().take(len).enumerate() {
buffer_slice[i] = item;
}
c_vec.drop()
}
Is there a simpler way to do this? Or a common library that can do this for me?
bindgen has nicely given me
extern "C" {
pub fn Hacl_Bignum4096_new_bn_from_bytes_be(len: u32, b: *mut u8) -> *mut u64;
}
returning something of type *mut u64. Unfortunately there is no reliable way (that I have found) to determine how many u64s are allocated. This makes is very hard (for me) to extract the data pointed to into something I can safely persist in a Rust struct instance.
As a consequence, any time I want to use any function from the Hacl library I have to perform that conversion and free up the created pointers in an unsafe block.
impl Bignum {
/// Returns true if self < other
pub fn lt(&self, other: &Bignum) -> Result<bool, Error> {
let hacl_result: HaclBnWord;
unsafe {
let a = self.get_hacl_bn()?;
let b = other.get_hacl_bn()?;
hacl_result = Hacl_Bignum4096_lt_mask(a, b);
free_hacl_bn(a);
free_hacl_bn(b);
}
Ok(hacl_result != 0 as HaclBnWord)
}
}
unsafe fn get_hacl_bn(&self) is suitably defined and calls Hacl_Bignum4096_new_bn_from_bytes_be() appropriately. And unsafe fn free_hacl_bn(bn: HaclBnType) also lives in this module.
I haven't benchmarked anything yet, but having to perform the conversion to a Hacl_Bignum from bytes each and every time feels wasteful.
So is there a way to determine the size of what is pointed to or is there a way to copy the data out of it into something safe?
You write: "having to perform the conversion to a Hacl_Bignum from bytes each and every time feels wasteful". It seems like you are not letting the library do its job. You should not keep a copy of the bignum data in your Rust struct Bignum, but only the pointer you get from the library. Something like:
extern "C" {
pub fn Hacl_Bignum4096_new_bn_from_bytes_be(len: u32, b: *mut u8) -> *mut u64;
pub fn Hacl_Bignum4096_lt_mask(a: *mut u64, b: *mut u64) -> u64;
}
struct Bignum {
handle: *mut u64,
}
struct BignumError {}
impl Bignum {
pub fn new(bytes: &mut [u8]) -> Result<Self, BignumError> {
unsafe {
let handle =
Hacl_Bignum4096_new_bn_from_bytes_be(bytes.len() as u32, bytes.as_mut_ptr());
if handle.is_null() {
return Err(BignumError {});
} else {
Ok(Self { handle })
}
}
}
/// Returns true if self < other
pub fn lt(&self, other: &Bignum) -> bool {
unsafe { Hacl_Bignum4096_lt_mask(self.handle, other.handle) == u64::MAX }
}
}
PS. I used the comments in this file, which seems to be the library in question.
There's the following line in C:
my_struct->ptr = (char*) data
where as you can see, my_struct has a ptr member of type char*
I have this on Rust:
struct MyStruct {
ptr: *mut libc::c_char
}
then I fill it like this:
unsafe{*my_struct}.ptr = Box::into_raw(my_data) as *mut libc::c_char;
unsafe{((*my_struct).ptr as *mut MyData).as_mut()}.unwrap();
but I'm getting either an unwrap panic on the line above. See that I acessed it immeidately after setting it, so no lifetime, out of scope problems for this data.
Here's the actual MyStruct:
https://github.com/mysql/mysql-server/blob/8.0/include/mysql/udf_registration_types.h#L69
I think the problem is resumed here:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=293ca891bedb9528ae840bcdf737777c
or in other words:
#[derive(Clone, Copy)]
struct MyStruct {
ptr: *mut libc::c_char
}
struct MyData{}
fn main() {
let my_struct = &mut MyStruct{
ptr: std::ptr::null_mut()
} as *mut MyStruct;
let my_data = Box::new(MyData{});
unsafe{*my_struct}.ptr = Box::into_raw(my_data) as *mut libc::c_char;
unsafe{((*my_struct).ptr as *mut MyData).as_mut()}.unwrap();
}
By doing unsafe{*my_struct}.ptr, you're copying *my_struct, then overwriting .ptr of that copy, which is why you're observing no change. Instead, write to (*my_struct).ptr:
unsafe {
(*my_struct).ptr = Box::into_raw(my_data) as *mut libc::c_char;
}
I am following up on Casting a borrowed reference with a lifetime to a raw pointer in Rust, which solved the wrong problem.
Please consider the following code:
extern crate jni;
extern crate ffi;
use jni::JNIEnv;
use jni::objects::JClass;
use jni::sys::{jint, jlong, jobject};
struct CameraAppEngine {
_env: *mut jni::sys::JNIEnv,
_width: i32,
_height: i32
}
impl CameraAppEngine {
pub fn new(_env: *mut jni::sys::JNIEnv, _width: i32, _height: i32) -> CameraAppEngine {
CameraAppEngine { _env, _width, _height }
}
pub fn create_camera_session(&mut self, surface: jobject) {
// error!
let window = ffi::ANativeWindow_fromSurface(self._env, surface);
}
}
fn app_engine_create(env: &JNIEnv, width: i32, height: i32) -> *mut CameraAppEngine {
let engine = CameraAppEngine::new(env.get_native_interface(), width, height);
Box::into_raw(Box::new(engine))
}
#[no_mangle]
pub extern "C" fn Java_io_waweb_cartoonifyit_MainActivity_createCamera(env: JNIEnv<'static>, _: JClass, width:jint, height:jint) -> jlong {
app_engine_create(&env, width, height) as jlong
}
#[no_mangle]
pub extern "C" fn Java_io_waweb_cartoonifyit_MainActivity_onPreviewSurfaceCreated(_: JNIEnv, _: JClass, engine_ptr:jlong, surface:jobject) {
let mut app = unsafe { Box::from_raw(engine_ptr as *mut CameraAppEngine) };
app.create_camera_session(surface);
}
And in the ffi crate we have:
extern "C" {
pub fn ANativeWindow_fromSurface(env: *mut JNIEnv, surface: jobject) -> *mut ANativeWindow;
}
This results in:
error[E0308]: mismatched types
--> native_app/src/lib.rs:24:53
|
| let window = ffi::ANativeWindow_fromSurface(self._env, surface);
| ^^^^^^^^^ expected struct `ffi::JNINativeInterface`, found struct `jni::sys::JNINativeInterface_`
|
= note: expected raw pointer `*mut *const ffi::JNINativeInterface`
found raw pointer `*mut *const jni::sys::JNINativeInterface_`
error[E0308]: mismatched types
--> native_app/src/lib.rs:24:64
|
| let window = ffi::ANativeWindow_fromSurface(self._env, surface);
| ^^^^^^^ expected enum `std::ffi::c_void`, found enum `jni::sys::_jobject`
|
= note: expected raw pointer `*mut std::ffi::c_void`
found raw pointer `*mut jni::sys::_jobject`
The problem is that the JNIEnv type expected by ANativeWindow_fromSurface is actually unrelated to jni::sys::JNIEnv entirely.
It's defined in ffi like so:
pub type JNIEnv = *const JNINativeInterface;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct JNINativeInterface {
pub reserved0: *mut ::std::os::raw::c_void,
pub reserved1: *mut ::std::os::raw::c_void,
pub reserved2: *mut ::std::os::raw::c_void,
pub reserved3: *mut ::std::os::raw::c_void,
pub GetVersion: ::std::option::Option<unsafe extern "C" fn(arg1: *mut JNIEnv) -> jint>,
pub DefineClass: ::std::option::Option<
unsafe extern "C" fn(
arg1: *mut JNIEnv,
arg2: *const ::std::os::raw::c_char,
arg3: jobject,
arg4: *const jbyte,
arg5: jsize,
) -> jclass,
>,
pub FindClass: ::std::option::Option<
unsafe extern "C" fn(arg1: *mut JNIEnv, arg2: *const ::std::os::raw::c_char) -> jclass,
>,
pub FromReflectedMethod:
::std::option::Option<unsafe extern "C" fn(arg1: *mut JNIEnv, arg2: jobject) -> jmethodID>,
pub FromReflectedField:
::std::option::Option<unsafe extern "C" fn(arg1: *mut JNIEnv, arg2: jobject) -> jfieldID>,
pub ToReflectedMethod: ::std::option::Option<
unsafe extern "C" fn(
arg1: *mut JNIEnv,
arg2: jclass,
arg3: jmethodID,
arg4: jboolean,
) -> jobject,
>
// etc...
}
Given the glue code shown in the example, how do I get a valid reference to ffi::JNIEnv so that I may pass it to the ANativeWindow_fromSurface method. Bonus points if you give advice on converting jni::sys::jobject to *mut std::os::raw::c_void (lifetime concerns, null pointers, etc.).
Full source to ffi definitions
Here is the basic helloworld implementation I used to prove the concept in the accepted answer:
use std::ffi::{CString, CStr};
use std::os::raw::{c_char};
/// Expose the JNI interface for android below
#[cfg(target_os="android")]
#[allow(non_snake_case)]
pub mod android {
extern crate ffi;
use super::*;
use self::ffi::{JNIEnv, jclass, jstring, jlong};
#[derive(Debug)]
struct AppEngine {
greeting: *mut c_char
}
unsafe fn rust_greeting(app: *mut AppEngine) -> *mut c_char {
let app = Box::from_raw(app);
app.greeting
}
/// Constructs an AppEngine object.
fn rust_engine_create(to: *const c_char) -> *mut AppEngine {
let c_str = unsafe { CStr::from_ptr(to) };
let recipient = match c_str.to_str() {
Err(_) => "there",
Ok(string) => string,
};
let greeting = CString::new("Hello ".to_owned() + recipient).unwrap().into_raw();
let app = AppEngine{greeting: greeting};
Box::into_raw(Box::new(app))
}
/// Destroys an AppEngine object previously constructed using `rust_engine_create()`.
unsafe fn rust_engine_destroy(app: *mut AppEngine) {
drop(Box::from_raw(app))
}
#[no_mangle]
pub unsafe extern fn Java_io_waweb_cartoonifyit_MainActivity_greeting(env: &mut JNIEnv, _: jclass, app_ptr: jlong) -> jstring {
let app = app_ptr as *mut AppEngine;
let new_string = env.as_ref().unwrap().NewStringUTF.unwrap();
new_string(env, rust_greeting(app))
}
#[no_mangle]
pub unsafe extern fn Java_io_waweb_cartoonifyit_MainActivity_createNativeApp(env: &mut JNIEnv, _: jclass, java_pattern: jstring) -> jlong {
let get_string_chars = env.as_ref().unwrap().GetStringChars.unwrap();
let is_copy = 0 as *mut u8;
rust_engine_create(get_string_chars(env, java_pattern, is_copy) as *const c_char ) as jlong
}
#[no_mangle]
pub unsafe extern "C" fn Java_io_waweb_cartoonifyit_MainActivity_destroyNativeApp(_: JNIEnv, _: jclass, app_ptr: jlong) {
let app = app_ptr as *mut AppEngine;
rust_engine_destroy(app)
}
}
This is just a proof of concept. More care should be taken when casting raw pointers about. Also see notes about Box::leak in the accepted answer.
A JNIEnv is a pointer to a struct used for communication between Java and native code. This communication ABI is implemented by pretty much every JVM(and android). There are multiple versions of the aforementioned structs, which is what the GetVersion field is for.
It seems to me that you are using an external jni crate along with your own ffi crate generated from this wrapper. I would expect your ffi crate to be the most correct since it is using android headers, instead of the standard JVM headers which a most likely being used by the jni crate.
One last note Box::from_raw(engine_ptr as *mut CameraAppEngine), creates a box which will free the memory located at engine_ptr. This is likely not what you want. Consider using Box::leak to leak the created Box and avoid use after frees.
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())
}
}