Array of raw pointers in a static space (FFI)

Is there any good way to represent a pointer hierarchy in a static context?

I'm working with a FFI that requires you to define a static struct for registration. That struct has a pointer to an array of pointers (null terminated), which each points to another struct. All in all, the rust representation looks about like this:

#![allow(non_camel_case_types)]

#[repr(C)]
struct inner_c_struct {
    a: *mut i32,
}

#[repr(C)]
struct outer_c_struct {
    arr: *mut *mut inner_c_struct,
}

static mut VAL: i32 = 100;

static INNER: inner_c_struct = inner_c_struct {
    a: unsafe { &mut VAL },
};

static ARR: [*mut inner_c_struct; 2] = [&INNER, std::ptr::null_mut()];

// This is the important part
static OUTER: outer_c_struct = outer_c_struct {
    arr: ARR.as_mut_ptr(),
};

That doesn't compile of course, since pointers aren't sync.But what is the best way to make this compile?

I've been using a UnsafeSyncCell<T>(UnsafeCell<T>) wrapper with Sync and Send that I"ve been using to wrap everything (so ARR: [UnsafeSyncCell<*mut T>; 2] and OUTER: UnsafeSyncCell<outer_c_struct>), but it is quite tedious to work with, with conversions among all the different pointer types.

Is there a better way to manage this?

If your goal is just to mark the types as Send or Sync you can just implement Send or Sync manually on the type

Playground

#[derive(Debug)]
struct Sendable(*mut usize);

unsafe impl Send for Sendable { }

fn main() { 
    let send = Sendable(std::ptr::null_mut());
    std::thread::spawn(move || println!("{send:?}")).join().unwrap();
}
1 Like

A simple Sendable looks nicer than my UnsafeSyncCell - I don't know why I was thinking I'd need the interior mutability, since it's never touched on the Rust side (well, VAL is but it's an AtomicI32 in real life).

It still has the yucky requirement that pointers have to be casted around a bit - but I don't think that's avoidable. Thanks!

If only the leaves of your struct tree are mutable this should work.

#![allow(non_camel_case_types)]

use std::sync::atomic::*;

#[repr(C)]
struct inner_c_struct {
    a: &'static AtomicI32,
}

#[repr(C)]
struct outer_c_struct {
    arr: &'static [Option<&'static inner_c_struct>],
}

static VAL: AtomicI32 = AtomicI32::new(100);

static OUTER: outer_c_struct = outer_c_struct {
    arr: &[
        Some(&inner_c_struct { a: &VAL,}),
        None
    ],
};
1 Like

Hey, that's great! Much simpler, I apprecaite it

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.