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

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
*/

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 constrain the lifetime when doing unsafe conversion

I want to create a Test ref from the array ref with the same size and keep the lifetime checking.
I can do this by using a function and I know the function can deduce the lifetime. The code below is intentionally designed to fail when compiling because of use after move. It works.
struct Test {
a: i32,
}
/// 'a can be removed for simplification
fn create_test<'a>(ptr: &'a mut [u8]) -> &'a mut Test {
assert_eq!(ptr.len(), size_of::<Test>());
unsafe { &mut *(ptr as *mut [u8] as *mut Test) }
}
fn main() {
let mut space = Box::new([0 as u8; 100]);
let (s1, _s2) = space.split_at_mut(size_of::<Test>());
let test = create_test(s1);
drop(space);
test.a += 1;
}
My question is how can I do this without declaring an extra function to constrain the lifetime.
fn main() {
let mut space = Box::new([0 as u8; 100]);
let (s1, _s2): (&'a mut [u8], _) = space.split_at_mut(size_of::<Test>());
let test: &'a mut Test = unsafe { &mut *(s1 as *mut [u8] as *mut Test) };
drop(space);
}
such `a is not allowed.
The following code works. And it holds the borrowing check.
fn main() {
let mut space = Box::new([0 as u8; 100]);
let layout = Layout::new::<Test>();
println!("{}", layout.align());
let (_prefix, tests, _suffix) = unsafe { space.align_to_mut::<Test>() };
assert!(tests.len() > 0);
let test = &mut tests[0];
let (_, suffix, _) = unsafe { tests[1..].align_to_mut::<u8>() };
}
You cannot do that, but this is not needed either. Lifetimes are used to ensure safety across function boundaries. In the same function you can just ensure safety manually.
Theoretically, we would not need a borrow checker if the compiler could just inspect the called functions and follow the execution path to deterime whether we invoke Undefined Behavior. Practically, this can't be done because of problems like the Halting Problem and performance.

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?

How to get the next pointer?

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

Precise memory layout control in Rust?

As far as I know, the Rust compiler is allowed to pack, reorder, and add padding to each field of a struct. How can I specify the precise memory layout if I need it?
In C#, I have the StructLayout attribute, and in C/C++, I could use various compiler extensions. I could verify the memory layout by checking the byte offset of expected value locations.
I'd like to write OpenGL code employing custom shaders, which needs precise memory layout. Is there a way to do this without sacrificing performance?
As described in the FFI guide, you can add attributes to structs to use the same layout as C:
#[repr(C)]
struct Object {
a: i32,
// other members
}
and you also have the ability to pack the struct:
#[repr(C, packed)]
struct Object {
a: i32,
// other members
}
And for detecting that the memory layout is ok, you can initialize a struct and check that the offsets are ok by casting the pointers to integers:
#[repr(C, packed)]
struct Object {
a: u8,
b: u16,
c: u32, // other members
}
fn main() {
let obj = Object {
a: 0xaa,
b: 0xbbbb,
c: 0xcccccccc,
};
let a_ptr: *const u8 = &obj.a;
let b_ptr: *const u16 = &obj.b;
let c_ptr: *const u32 = &obj.c;
let base = a_ptr as usize;
println!("a: {}", a_ptr as usize - base);
println!("b: {}", b_ptr as usize - base);
println!("c: {}", c_ptr as usize - base);
}
outputs:
a: 0
b: 1
c: 3
There's no longer to_uint. In Rust 1.0, the code can be:
#[repr(C, packed)]
struct Object {
a: i8,
b: i16,
c: i32, // other members
}
fn main() {
let obj = Object {
a: 0x1a,
b: 0x1bbb,
c: 0x1ccccccc,
};
let base = &obj as *const _ as usize;
let a_off = &obj.a as *const _ as usize - base;
let b_off = &obj.b as *const _ as usize - base;
let c_off = &obj.c as *const _ as usize - base;
println!("a: {}", a_off);
println!("b: {}", b_off);
println!("c: {}", c_off);
}
You also can set memory layout for "data-carrying enums" like this.
#[repr(Int)]
enum MyEnum {
A(u32),
B(f32, u64),
C { x: u32, y: u8 },
D,
}
Details are described in manual and RFC2195.
https://rust-lang.github.io/unsafe-code-guidelines/layout/enums.html
https://rust-lang.github.io/rfcs/2195-really-tagged-unions.html#motivation

Resources