Cannot use downcast Any to an array containing references - rust

Passing just an array seems to work fine:
fn set_zero<'a>(u: &'a u32, ms: &mut [Option<&'a u32>; 4]) {
ms[0] = Some(u);
}
I'm trying to wrap C callback function which is passed a void *
so I'm using std::any::Any instead of an array:
fn set_zero<'a>(u: &'a u32, ma: &mut Any) {
if let Some(ms) = ma.downcast_mut::<[Option<&'a u32>; 4]>() {
ms[0] = Some(u);
}
}
This causes an error related to lifetimes:
error[E0477]: the type `[std::option::Option<&'a u32>; 4]`
does not fulfill the required lifetime
--> option.rs:18:26
|
18 | if let Some(ms) = ma.downcast_mut::<[Option<&'a u32>; 4]>() {
| ^^^^^^^^^^^^
|
= note: type must outlive the static lifetime
How can I fix this? What documentation should read to understand the error better?
UPDATE: more detailed background:
An contrived C prototype is - foo.c:
#include <stdint.h>
typedef int (*cb_t)(const uint32_t *obj, void *arg);
int32_t cb_run(uint32_t const objs[], uint32_t len, cb_t cb, void *arg)
{
int i;
for (i = 0; i < len; i++)
if (cb(&objs[i], arg) < 0)
return -1;
return 0;
}
Then, I tried to wrap by using Any:
extern crate libc;
use libc::{c_int, size_t, c_void};
use std::any::Any;
type CbT = extern "C" fn(obj: *const u32, arg: *mut c_void) -> c_int;
extern { fn cb_run(objs: *const u32, len: size_t, cb: CbT, arg: *mut c_void) -> c_int; }
type Cb = fn(obj: &u32, arg: &mut Any) -> i32;
struct CbData <'a> {
cb: Cb,
arg: &'a mut Any,
}
extern fn rust_cb(obj: *const u32, arg: *mut c_void) -> c_int {
unsafe {
let s = &mut *(arg as *mut CbData);
(s.cb)(&*obj, s.arg)
}
}
fn cb_run_rs(objs: &[u32], cb: Cb, arg: &mut Any) -> i32 {
let mut arg = &mut CbData{ cb: cb, arg: arg } ;
unsafe { cb_run(objs.as_ptr() as *const u32, objs.len() as size_t,
rust_cb, arg as *mut _ as *mut c_void) as i32 }
}
//// the above is lib, the below is bin
// set_zero() in the above
fn my_cb<'a>(obj: &'a u32, arg: &mut Any) -> i32 {
if let Some(data) = arg.downcast_mut::<[Option<&'a u32>; 4]>() {
data[0] = Some(obj);
}
0
}
fn main() {
let objs = [0u32, 1, 2, 3];
let mut arg = [None; 4];
println!("pre : {:?}", arg);
cb_run_rs(&objs, my_cb, &mut arg);
println!("post : {:?}", arg);
}
And it causes note: type must outlive the static lifetime.
How can I handle this kind of void * in good manner without unsafe from library user?

I can only tell it seems to work. main.rs
extern crate libc;
use libc::{c_int, size_t, c_void};
type CbT = extern "C" fn(obj: *const u32, arg: *mut c_void) -> c_int;
extern { fn cb_run(objs: *const u32, len: size_t, cb: CbT, arg: *mut c_void) -> c_int; }
type Cb <'a, T: ?Sized> = fn(obj: &'a u32, arg: &mut T) -> i32;
struct CbData <'a, 'b, T: 'a + 'b + ?Sized> {
cb: Cb<'a, T>,
arg: &'b mut T,
}
extern fn rust_cb<T: ?Sized>(obj: *const u32, arg: *mut c_void) -> c_int {
unsafe {
let s = &mut *(arg as *mut CbData<T>);
(s.cb)(&*obj, s.arg)
}
}
fn cb_run_rs<'a, 'b, T: 'a + ?Sized>(objs: &[u32], cb: Cb<'a, T>, arg: &'b mut T) -> i32 {
let mut arg = &mut CbData{ cb: cb, arg: arg } ;
unsafe { cb_run(objs.as_ptr() as *const u32, objs.len() as size_t,
rust_cb::<T>, arg as *mut _ as *mut c_void) as i32 }
}
//// the above is lib, the below is bin
fn my_cb<'a>(obj: &'a u32, arg: &mut [Option<&'a u32>]) -> i32 {
arg[*obj as usize] = Some(obj);
0
}
fn main() {
let objs = [0u32, 1, 2, 3];
let mut arg = [None; 4];
println!("pre : {:?}", arg);
cb_run_rs(&objs, my_cb, &mut arg);
println!("post : {:?}", arg);
}
FYI build.rs:
extern crate gcc;
fn main() {
gcc::compile_library("libfoo.a", &["src/foo.c"]);
}
Cargo.toml:
[package]
name = "sof"
version = "0.1.0"
authors = ["author#example.com"]
build = "build.rs"
[build-dependencies]
gcc = "0.3"
[dependencies]
libc = "0.2"

Related

using C function that takes pointer to C struct typedef in Rust

I'm trying to use bindings generated for cuBLAS using bindgen. Here's what my code looks like:
mod tests {
use super::*;
#[test]
pub fn alpha () {
let mut handle: cublasHandle_t;
let mut stat: cublasStatus_t;
let mut cudaStat: cudaError_t;
... some stuff
unsafe {
cudaStat = cudaMalloc(a.as_mut_ptr() as *mut *mut c_void, a.len() as u64);
cudaStat = cudaMalloc(b.as_mut_ptr() as *mut *mut c_void, b.len() as u64);
cudaStat = cudaMalloc(c.as_mut_ptr() as *mut *mut c_void, c.len() as u64);
stat = cublasCreate_v2(handle as *mut *mut cublasContext);
}
...some stuff
}
}
I get this error:
error: expected expression, found keyword `mut`
--> src/lib.rs:44:37
|
44 | stat = cublasCreate_v2(handle as *mut *mut cublasContext);
| ^^^ expected expression
error: could not compile `cublas-rs` due to previous error
NOTE: cublasHandle_t is a typedef for *mut cublasContext.
I've tried doing just &handle, *mut handle, etc but no dice.
cublasHandle_t is only supposed to be initialized by cublasCreate_v2.
Here's what things look like in bindings.rs:
// cublasContext struct we want to pass to cublasCreate_v2
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct cublasContext {
_unused: [u8; 0],
}
// alternative typedef used by cublas
pub type cublasHandle_t = *mut cublasContext;
// function to create a cublas handle
extern "C" {
pub fn cublasCreate_v2(handle: *mut cublasHandle_t) -> cublasStatus_t;
}
I've tried initializing it like this:
let mut handle: cublasHandle_t = *mut cublasContext { _unused: [] }; // no luck
let mut handle: cublasHandle_t = cublasContext { _unused: [] } as *mut cublasContext; // no
How do I call a function like this?
Actually, you probably want to just set handle to a null pointer to start with, since you say cublasCreate_v2 is supposed to create the handle.
mod tests {
use super::*;
pub fn alpha () {
// initialize with null pointer
let mut handle: cublasHandle_t = std::ptr::null_mut();
let mut stat: cublasStatus_t;
// ... some stuff
unsafe {
cudaStat = cudaMalloc(a.as_mut_ptr() as *mut *mut c_void, a.len() as u64);
cudaStat = cudaMalloc(b.as_mut_ptr() as *mut *mut c_void, b.len() as u64);
cudaStat = cudaMalloc(c.as_mut_ptr() as *mut *mut c_void, c.len() as u64);
// pass pointer to the pointer, using `&mut x`
stat = cublasCreate_v2(&mut handle);
}
// ...some stuff
}
}
You need to create the context as a variable first, before creating a pointer to it. To create a pointer to a value, you use &mut value, similar to &value in C.
mod tests {
use super::*;
pub fn alpha () {
let mut context = cublasContext { _unused: [] }; // create context
// get pointer to context, `&mut x` can be assigned to `*mut x`
let mut handle: cublasHandle_t = &mut context;
let mut stat: cublasStatus_t;
// ... some stuff
unsafe {
cudaStat = cudaMalloc(a.as_mut_ptr() as *mut *mut c_void, a.len() as u64);
cudaStat = cudaMalloc(b.as_mut_ptr() as *mut *mut c_void, b.len() as u64);
cudaStat = cudaMalloc(c.as_mut_ptr() as *mut *mut c_void, c.len() as u64);
// pass double-pointer, using `&mut x` again
stat = cublasCreate_v2(&mut handle);
}
// ...some stuff
}
}
You might want to add #[derive(Default)] to cublasContext, so you can do cublasContext::default() instead of needing to set up _unused.

How to fill Rust function pointer from C++

I want to call C++ from Rust. C++ then allocates and fills a buffer, then Rust uses it and deallocates. However, I'd like to deliver back the function pointer to deallocate the data. This is what I tried:
In Rust:
extern "C" {
pub fn openvpn_receive(
instance: *mut OpenVpnInstance,
size: *mut size_t,
deallocate: extern "C" fn(*mut u8),
) -> *mut u8;
}
fn main() {
let size: *mut size_t;
let deallocate = extern "C" fn(*mut u8);
let data: *mut u8 = openvpn_receive(self.instance, size, deallocate);
//use data
deallocate(data);
}
In C++:
uint8_t* openvpn_receive(size_t *size, void (*deallocate_function)(uint8_t *))
{
deallocate_function = &cpp_deallocate_u8;
uint8*t data = receive_data(size);
}
But the Rust code is not valid. How can I make such thing happen?
Maybe it will help You.
https://doc.rust-lang.org/std/keyword.extern.html
https://rust-embedded.github.io/book/interoperability/rust-with-c.html
C++ -> C -> Rust
use libc::{size_t, c_void};
#[repr(C)]
pub struct OpenVpnInstance();
//#[link(name = "your_c_library")]
extern "C" {
pub fn openvpn_receive(
instance: *mut OpenVpnInstance,
size: *mut size_t,
deallocate: *mut c_void,
) -> *mut u8;
}
pub fn my_callback(arg: *mut u8)
{
println!("CB!");
}
fn main()
{
let size: size_t = 42;
let instance = OpenVpnInstance{};
let dummy_arg: u8 = 42;
unsafe {
let cb = my_callback as *mut c_void;
let instance_ptr = &instance as *const _ as *mut OpenVpnInstance;
let arg_ptr = &dummy_arg as *const _ as *mut u8;
openvpn_receive(instance_ptr, size as *mut size_t, cb);
my_callback(arg_ptr)
}
}

How to get a mutable u32 pointer and cast it into an int pointer of C

Let's say I have a C function:
void func(char *buf, unsigned int *len);
To call it in Rust, I declared:
pub fn func(buf: *mut ::std::os::raw::c_char, len: *mut ::std::os::raw::c_uint) {
unimplemented!()
}
Then I wrote another wrapper:
pub fn another_func() -> String {
let mut capacity: u32 = 256;
let mut vec = Vec::with_capacity(capacity as usize);
unsafe {
func(vec.as_ptr() as *mut c_char, &capacity as *mut c_uint)
};
String::from_utf8(vec).unwrap();
unimplemented!()
}
But the compiler told me:
error[E0606]: casting `&u32` as `*mut u32` is invalid
--> src/main.rs:...:28
|
307 | &capacity as *mut c_uint)
Why can't I cast capacity into *mut c_unit?
It turns out I have to make the reference mutable.
func(vec.as_ptr() as *mut c_char, &mut capacity as *mut c_uint)

Is it possible for an extern "C" function to have access to a Rust closure? [duplicate]

I'm trying to write a Rusty wrapper for a piece of C API. There is one C construct I struggle with:
typedef bool (*listener_t) (int, int);
bool do_it(int x1, int y1, int x2, int y2, listener_t listener)
The function does its job for a range of numbers unless the listener returns false. In that case it aborts computation. I want to have a Rust wrapper like this:
fn do_with_callback<F>(start: (i32, i32), end: (i32, i32), callback: F)
where F: Fn(i32, i32) -> bool
rust-bindgen created this for me, slightly edited for clarity:
pub type listener_t = Option<extern "C" fn(x: c_int, y: c_int) -> c_bool>;
pub fn TCOD_line(xFrom: c_int, yFrom: c_int,
xTo: c_int, yTo: c_int,
listener: listener_t) -> c_bool;
How should I convert a closure or a trait reference to a C-style callback in my do_with functions:
pub fn do_with_callback<F>(start: (i32, i32), end: (i32, i32), callback: F) -> Self
where F: Fn(i32, i32) -> bool
{
let wrapper = ???;
unsafe {
ffi::do_it(start.0, start.1, end.0, end.1, Some(wrapper))
};
}
You cannot do it unless the C API allows passing a user-provided callback parameter. If it does not, you can only use static functions.
The reason is that closures are not "just" functions. As their name implies, closures "close over" variables from their lexical scope. Each closure has an associated piece of data which holds either values of captured variables (if the move keyword is used) or references to them. This data can be thought of as some unnamed, anonymous struct.
The compiler automatically adds an implementation of the corresponding Fn* traits for these anonymous structs. As you can see, methods on these traits accept self in addition to the closure arguments. In this context, self is the struct on which the trait is implemented. This means that each function which corresponds to a closure also has an additional parameter which contains the closure environment.
If your C API only allows you to pass functions without any user-defined parameters, you cannot write a wrapper which would allow you to use closures. I guess it may be possible to write some global holder for the closures environment, but I doubt it would be easy and safe.
If your C API does allow passing a user-defined argument, then it is possible to do what you want with trait objects:
extern crate libc;
use std::mem;
use libc::{c_int, c_void};
extern "C" {
fn do_something(f: Option<extern "C" fn(x: c_int, arg: *mut c_void) -> c_int>, arg: *mut c_void) -> c_int;
}
extern "C" fn do_something_handler(x: c_int, arg: *mut c_void) -> c_int {
let closure: &mut &mut dyn FnMut(i32) -> bool = unsafe { mem::transmute(arg) };
closure(x as i32) as c_int
}
pub fn do_with_callback<F>(x: i32, mut callback: F) -> bool
where F: FnMut(i32) -> bool
{
// reason for double indirection is described below
let mut cb: &mut dyn FnMut(i32) -> bool = &mut callback;
let cb = &mut cb;
unsafe { do_something(Some(do_something_handler), cb as *mut _ as *mut c_void) > 0 }
}
This will only work if do_something does not store the pointer to the callback somewhere. If it does, you need to use a Box<Fn(..) -> ..> trait object and leak it after you pass it to the function. Then, if possible, it should be obtained back from your C library and disposed of. It could look like this:
extern crate libc;
use std::mem;
use libc::{c_int, c_void};
extern "C" {
fn set_handler(f: Option<extern "C" fn(x: c_int, arg: *mut c_void) -> c_int>, arg: *mut c_void);
fn invoke_handler(x: c_int) -> c_int;
fn unset_handler() -> *mut c_void;
}
extern "C" fn do_something_handler(x: c_int, arg: *mut c_void) -> c_int {
let closure: &mut Box<dyn FnMut(i32) -> bool> = unsafe { mem::transmute(arg) };
closure(x as i32) as c_int
}
pub fn set_callback<F>(callback: F)
where F: FnMut(i32) -> bool,
F: 'static
{
let cb: Box<Box<dyn FnMut(i32) -> bool>> = Box::new(Box::new(callback));
unsafe {
set_handler(Some(do_something_handler), Box::into_raw(cb) as *mut _);
}
}
pub fn invoke_callback(x: i32) -> bool {
unsafe { invoke_handler(x as c_int) > 0 }
}
pub fn unset_callback() {
let ptr = unsafe { unset_handler() };
// drop the callback
let _: Box<Box<dyn FnMut(i32) -> bool>> = unsafe { Box::from_raw(ptr as *mut _) };
}
fn main() {
let mut y = 0;
set_callback(move |x| {
y += 1;
x > y
});
println!("First: {}", invoke_callback(2));
println!("Second: {}", invoke_callback(2));
unset_callback();
}
Double indirection (i.e. Box<Box<...>>) is necessary because Box<Fn(..) -> ..> is a trait object and therefore a fat pointer, incompatible with *mut c_void because of different size.
The first snippet from Vladimir Matveev no longer works as written. The size of &mut FnMut(i32) -> bool and *mut c_void is different and such casts lead to a crash. Corrected example (playpen):
extern crate libc;
use std::mem::*;
use libc::c_void;
pub fn run<F>(mut callback: F) -> bool
where F: FnMut(i32) -> bool
{
let mut cb: &mut FnMut(i32) -> bool = &mut callback;
println!("sizeof(cb/*-ptr): {}/{}",
size_of::<*mut FnMut(i32) -> bool>(),
size_of::<*mut c_void>());
let ctx = &mut cb as *mut &mut FnMut(i32) -> bool as *mut c_void;
println!("ctx: {:?}", ctx);
//----------------------------------------------------------
// Convert backward
let cb2: *mut *mut FnMut(i32) -> bool = unsafe { transmute(ctx) };
println!("cb2: {:?}", cb2);
// this is more useful, but can't be printed, because not implement Debug
let closure: &mut &mut FnMut(i32) -> bool = unsafe { transmute(ctx) };
closure(0xDEAD)
}
fn main() {
println!("answer: {}",
run(|x| {
println!("What can change nature of a man?");
x > 42
}));
}
In C, a function pointer does not have associated context, which is why usually a C callback function usually carry an extra void* argument pass the context...
typedef bool (*listener_t)(int, int, void* user_data);
bool do_it(void* user_data, int x1, int y1, int x2, int y2, listener_t listener)
... or have an API to let to store the user data...
void api_set_user_data(void* user_data); // <-- caller set the context
void* api_get_user_data(); // <-- callback use this to retrieve context.
If the library you want to wrap does not provide any of the above, you will need to pass the context via other channels, e.g. via a global variable, though that context will be shared across the whole process:
lazy_static! {
static ref REAL_CALLBACK: Mutex<Option<Box<FnMut(c_int, c_int) -> bool + Send>>> = Default::default();
}
extern "C" fn callback(x: c_int, y: c_int) -> bool {
if let Some(ref mut real_callback) = *REAL_CALLBACK.lock().unwrap() {
real_callback(x, y)
} else {
panic!("<handle error here>");
}
}
fn main() {
*REAL_CALLBACK.lock().unwrap() = Some(Box::new(move |x, y| {
println!("...");
true
}));
unsafe {
do_it(callback);
}
}
It is also possible to create a trampoline function to stick the context directly in the function, but it is extremely difficult and unsafe.
Answer manually migrated from https://stackoverflow.com/a/42597209/224671

Is there a way to determine the offsets of each of the trait methods in the VTable?

I thought I could try more or less build a trait object from scratch without using the impl blocks. To elaborate:
trait SomeTrait {
fn fn_1(&self);
fn fn_2(&self, a: i64);
fn fn_3(&self, a: i64, b: i64);
}
struct TraitObject {
data: *mut (),
vtable: *mut (),
}
fn dtor(this: *mut ()) {
// ...
}
fn imp_1(this: *mut ()) {
// ...
}
fn imp_2(this: *mut (), a: i64) {
// ...
}
fn imp_3(this: *mut (), a: i64, b: i64) {
// ...
}
fn main() {
let data = &... as *mut (); // something to be the object
let vtable = [dtor as *mut (),
8 as *mut (),
8 as *mut (),
imp_1 as *mut (),
imp_2 as *mut (),
imp_3 as *mut ()]; // ignore any errors in typecasting,
//this is not what I am worried about getting right
let to = TraitObject {
data: data,
vtable: vtable.as_ptr() as *mut (),
};
// again, ignore any typecast errors,
let obj: &SomeTrait = unsafe { mem::transmute(to) };
// ...
obj.fn_1();
obj.fn_2(123);
obj.fn_3(123, 456);
}
From what I understand, the order in which the member functions appear in the trait definition is not always the same as the function pointers appear in the VTable. Is there a way to determine the offsets of each of the trait methods in the VTable?
If you don't mind detecting the layout at runtime, then you can compare the function addresses at specific offsets and compare them to the addresses of a known, dummy implementation to match them up. This assumes that you know how many methods there are in the trait, since you may need to read all of them.
use std::mem;
trait SomeTrait {
fn fn_1(&self);
fn fn_2(&self, a: i64);
fn fn_3(&self, a: i64, b: i64);
}
struct Dummy;
impl SomeTrait for Dummy {
fn fn_1(&self) { unimplemented!() }
fn fn_2(&self, _a: i64) { unimplemented!() }
fn fn_3(&self, _a: i64, _b: i64) { unimplemented!() }
}
struct TraitObject {
data: *mut (),
vtable: *mut (),
}
fn main() {
unsafe {
let fn_1 = Dummy::fn_1 as *const ();
let fn_2 = Dummy::fn_2 as *const ();
let fn_3 = Dummy::fn_3 as *const ();
let dummy = &mut Dummy as &mut SomeTrait;
let dummy: TraitObject = mem::transmute(dummy);
let vtable = dummy.vtable as *const *const ();
let vtable_0 = *vtable.offset(3);
let vtable_1 = *vtable.offset(4);
let vtable_2 = *vtable.offset(5);
// Mapping vtable offsets to methods is left as an exercise to the reader. ;)
println!("{:p} {:p} {:p}", fn_1, fn_2, fn_3);
println!("{:p} {:p} {:p}", vtable_0, vtable_1, vtable_2);
}
}

Resources