How to get the next pointer? - rust

I have a function implemented in C, and I want to write a function in Rust with the same interface. The function receives a pointer to the beginning of the array (win8_t *) and the length of the array. I need to be able to run through the array.
There must be a better way to get the next value, but now I can do this strange thing:
use std::mem;
pub extern "C" fn print_next(i: *const u8) {
let mut ii = unsafe { mem::transmute::<*const u8, i64>(i) };
ii += 1;
let iii = unsafe { mem::transmute::<i64, *const u8>(ii) };
let jj = unsafe { *iii };
println!("{}", jj); // jj is next value
}

As Shepmaster said, you probably need to provide the length of the slice.
Most of the time you're working with pointers, your function will be unsafe (because you usually need to dereference it at some point). It might be a good idea to mark them unsafe to delegate the safety responsibility to the caller.
Here are some examples using offset and from_raw_slice:
use std::mem;
use std::slice;
// unsafe!
pub extern "C" fn print_next(i: *const u8) {
let mut ii = unsafe { mem::transmute::<*const u8, i64>(i) };
ii += 1;
let iii = unsafe { mem::transmute::<i64, *const u8>(ii) };
let jj = unsafe { *iii };
println!("{}", jj); // jj is next value
}
// unsafe!
pub unsafe extern "C" fn print_next2(i: *const u8) {
let j = *i.offset(1);
println!("{}", j);
}
// (less but still ...) unsafe!
pub unsafe extern "C" fn print_next3(i: *const u8, len: usize) {
let slice = slice::from_raw_parts(i, len);
// we are not checking the size ... so it may panic!
println!("{}", slice[1]);
}
fn main() {
let a = [9u8, 4, 6, 7];
print_next(&a as *const u8);
unsafe {
print_next2(&a[1] as *const u8);
print_next3(&a[2] as *const u8, 2);
}
// what if I print something not in a??
print_next(&a[3] as *const u8); // BAD
unsafe {
print_next2(&a[3] as *const u8); // BAD
print_next3(&a[3] as *const u8, 2); // as bad as others, length is wrong
print_next3(&a[3] as *const u8, 1); // panic! out of bounds
}
}

Related

How can I cast &&T to *const *const T?

let val = &&10;
let ptr_ptr = val as *const *const i32; // casting `&&i32` as `*const *const i32` is invalid
I've thought that &&10 reserves 3 elements on a stack: 4 byte for value and 8 + 8 bytes for two pointers on x64. So, why there is a compiler error?
The following example, till the error, is a decomposition of your attempt.
Your attempt to convert references to pointers seems correct because this section of the reference states
Pointers and references have the same layout
The as conversion you wrote implies two conversions at once.
This section of the reference gives a table of the conversions as can perform.
We find &T to *const T (interpreting the footnotes of the table), but not &&T to *const *const T because &T is not *const T (we need another conversion for that).
You can perform them as in the next expression, or decompose in many stages.
fn main() {
let val = 10;
let ref_val = &val;
let ref_ref_val = &ref_val;
// let ptr_ptr_val = ref_ref_val as *const *const i32; // ERROR
//
let ptr_ptr_val = ref_ref_val as *const &i32 as *const *const i32;
println!("{} {}", **ref_ref_val, unsafe { **ptr_ptr_val });
//
let ptr_ptr_val = &&10 as *const &i32 as *const *const i32;
println!("{}", unsafe { **ptr_ptr_val });
//
let ptr_ptr_val: *const *const i32 = &(&10 as *const i32);
println!("{}", unsafe { **ptr_ptr_val });
//
let ptr_val = ref_val as *const i32;
let ref_ptr_val = &ptr_val;
let ptr_ptr_val = ref_ptr_val as *const *const i32;
println!("{} {}", **ref_ref_val, unsafe { **ptr_ptr_val });
}
/*
10 10
10
10
10 10
*/

How to return Rust Vec of unknown size over FFI?

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?

Equivalent of struct->ptr = (char*) data in rust

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;
}

Returning array from Rust to FFI

I need to write a function that returns array of u16 integers in Rust. This function then should be used by FFI.
extern crate libc;
use libc::{uint16_t};
#[no_mangle]
pub extern fn ffi_test() -> *const uint16_t {
let test: [u16;4] = [1,2,3,4];
test.as_ptr()
}
Rust code compiles without errors. I used Ruby to test the ffi call:
# coding: utf-8
require 'ffi'
module MyMod
extend FFI::Library
ffi_lib 'my_ffi_test_lib'
attach_function :ffi_test, [], :pointer
end
a_ptr = MyMod.ffi_test
size = 4
result_array = a_ptr.read_array_of_uint16(size)
p result_array
But the results are totally wrong (expected: [1, 2, 3, 4]):
$ ruby ffi_test.rb
[57871, 25191, 32767, 0]
As if I am reading totally diffirent memory addr. I assume maybe that I should not use #as_ptr() on Rust array?
EDIT
As per recommendation of #FrenchBoiethios I tried to box the array:
extern crate libc;
use libc::{uint16_t};
#[no_mangle]
pub extern fn ffi_test() -> *mut uint16_t {
let test: [u16;4] = [1,2,3,4];
let b = Box::new(test);
Box::into_raw(b)
}
This gives compile error:
note: expected type `std::boxed::Box<u16>`
found type `std::boxed::Box<[u16; 4]>`
Your array is on the stack, so there is a lifetime issue when you returns it as a pointer (returned pointer to a local variable). You must allocate it in the heap:
#[no_mangle]
pub extern "C" fn ffi_test() -> *mut u16 {
let mut test = vec![1, 2, 3, 4];
let ptr = test.as_mut_ptr();
std::mem::forget(test); // so that it is not destructed at the end of the scope
ptr
}
or
#[no_mangle]
pub extern "C" fn ffi_test() -> *mut u16 {
let test = Box::new([1u16, 2, 3, 4]); // type must be explicit here...
Box::into_raw(test) as *mut _ // ... because this cast can convert
// *mut [i32; 4] to *mut u16
}
I am trying to learn Rust ffi, those implementations are a frankenstein creation from different sources in internet. So take it with a grain of salt.
Currently I am with two approaches:
a) Remove the array from rust GC and return the point. User need to promise to call free later.
#[repr(C)]
pub struct V2 {
pub x: i32,
pub y: i32,
}
#[repr(C)]
struct Buffer {
len: i32,
data: *mut V2,
}
#[no_mangle]
extern "C" fn generate_data() -> Buffer {
let mut buf = vec![V2 { x: 1, y: 0 }, V2 { x: 2, y: 0}].into_boxed_slice();
let data = buf.as_mut_ptr();
let len = buf.len() as i32;
std::mem::forget(buf);
Buffer { len, data }
}
#[no_mangle]
extern "C" fn free_buf(buf: Buffer) {
let s = unsafe { std::slice::from_raw_parts_mut(buf.data, buf.len as usize) };
let s = s.as_mut_ptr();
unsafe {
Box::from_raw(s);
}
}
b) Send the array through FFI callback function. User need to promise to not keep references, but dont need to call free.
#[no_mangle]
pub extern "C" fn context_get_byte_responses(callback: extern "stdcall" fn (*mut u8, i32)) -> bool {
let bytes: Vec<u8> = vec![];
callback(bytes.as_mut_ptr(), bytes.len() as i32);
true
}

Creating a Vec in Rust from a C array pointer and safely freeing it?

I'm calling a C function from Rust which takes a null pointer as as an argument, then allocates some memory to point it to.
What is the correct way to efficiently (i.e. avoiding unnecessary copies) and safely (i.e. avoid memory leaks or segfaults) turn data from the C pointer into a Vec?
I've got something like:
extern "C" {
// C function that allocates an array of floats
fn allocate_data(data_ptr: *mut *const f32, data_len: *mut i32);
}
fn get_vec() -> Vec<f32> {
// C will set this to length of array it allocates
let mut data_len: i32 = 0;
// C will point this at the array it allocates
let mut data_ptr: *const f32 = std::ptr::null_mut();
unsafe { allocate_data(&mut data_ptr, &mut data_len) };
let data_slice = unsafe { slice::from_raw_parts(data_ptr as *const f32, data_len as usize) };
data_slice.to_vec()
}
If I understand correctly, .to_vec() will copy data from the slice into a new Vec, so the underlying memory will still need to be freed (as the underlying memory for the slice won't be freed when it's dropped).
What is the correct approach for dealing with the above?
can I create a Vec which takes ownership of the underlying memory, which is freed when the Vec is freed?
if not, where/how in Rust should I free the memory that the C function allocated?
anything else in the above that could/should be improved on?
can I create a Vec which takes ownership of the underlying memory, which is freed when the Vec is freed?
Not safely, no. You must not use Vec::from_raw_parts unless the pointer came from a Vec originally (well, from the same memory allocator). Otherwise, you will try to free memory that your allocator doesn't know about; a very bad idea.
Note that the same thing is true for String::from_raw_parts, as a String is a wrapper for a Vec<u8>.
where/how in Rust should I free the memory that the C function allocated?
As soon as you are done with it and no sooner.
anything else in the above that could/should be improved on?
There's no need to cast the pointer when calling slice::from_raw_parts
There's no need for explicit types on the variables
Use ptr::null, not ptr::null_mut
Perform a NULL pointer check
Check the length is non-negative
use std::{ptr, slice};
extern "C" {
fn allocate_data(data_ptr: *mut *const f32, data_len: *mut i32);
fn deallocate_data(data_ptr: *const f32);
}
fn get_vec() -> Vec<f32> {
let mut data_ptr = ptr::null();
let mut data_len = 0;
unsafe {
allocate_data(&mut data_ptr, &mut data_len);
assert!(!data_ptr.is_null());
assert!(data_len >= 0);
let v = slice::from_raw_parts(data_ptr, data_len as usize).to_vec();
deallocate_data(data_ptr);
v
}
}
fn main() {}
You didn't state why you need it to be a Vec, but if you never need to change the size, you can create your own type that can be dereferenced as a slice and drops the data when appropriate:
use std::{ptr, slice};
extern "C" {
fn allocate_data(data_ptr: *mut *const f32, data_len: *mut i32);
fn deallocate_data(data_ptr: *const f32);
}
struct CVec {
ptr: *const f32,
len: usize,
}
impl std::ops::Deref for CVec {
type Target = [f32];
fn deref(&self) -> &[f32] {
unsafe { slice::from_raw_parts(self.ptr, self.len) }
}
}
impl Drop for CVec {
fn drop(&mut self) {
unsafe { deallocate_data(self.ptr) };
}
}
fn get_vec() -> CVec {
let mut ptr = ptr::null();
let mut len = 0;
unsafe {
allocate_data(&mut ptr, &mut len);
assert!(!ptr.is_null());
assert!(len >= 0);
CVec {
ptr,
len: len as usize,
}
}
}
fn main() {}
See also:
How to convert a *const pointer into a Vec to correctly drop it?
Is it possible to call a Rust function taking a Vec from C?

Resources