3

I'm programming a driver in rust and I have the following C struct which I need to convert to something equivalent in Rust:

struct vfio_irq_set {
    __u32   argsz;
    __u32   flags;
    __u32   index;
    __u32   start;
    __u32   count;
    __u8    data[];
};

The only variable that causes me some problems is the data array. So far I have the following rust structure:

#[allow(non_camel_case_types)]
#[repr(C)]
struct vfio_irq_set {
    argsz: u32,
    flags: u32,
    index: u32,
    start: u32,
    count: u32,
    data: *const u8,
}

The rust code to initialize the structure and make the ioctl call looks the following:

let irq_set: vfio_irq_set = vfio_irq_set {
    argsz: (mem::size_of::<vfio_irq_set>() + mem::size_of::<RawFd>() * (MAX_INTERRUPT_VECTORS + 1) as usize) as u32,
    count: interrupt_vector,
    flags: VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER,
    index: VFIO_PCI_MSIX_IRQ_INDEX as u32,
    start: 0,
    data: &[event_fd as u8] as *const u8,
};

if unsafe { libc::ioctl(device_fd, VFIO_DEVICE_SET_IRQS, &irq_set) } == -1 {
    return Err(format!(
        "failed to VFIO_DEVICE_SET_IRQS. Errno: {}",
        unsafe { *libc::__errno_location() }
    ).into());
}

But I always get back a "failed to VFIO_DEVICE_SET_IRQS. Errno: 22".

Does someone have an idea on what I'm doing wrong?

tzwickl
  • 1,341
  • 2
  • 15
  • 31
  • They're not going to have the same layout. Flexible data members should be in contiguous memory with the rest of the structure, and should only take the required space needed to store the data. Your example does not do that. A pointer always takes space, takes a fixed amount of space, and any data pointed to it is not contiguous with the rest of the struct. – Alex Huszagh Sep 01 '19 at 21:26
  • 2
    Also, `&[event_fd as u8] as *const u8` is likely unsafe: the array is temporary and doesn't live long enough. – mcarton Sep 01 '19 at 21:30
  • You're also going to lose size information, so it has no way to safely read that data even if the data wasn't temporary. – Alex Huszagh Sep 01 '19 at 21:32
  • 1
    Yes, you are both right this was just a desperate way to solve this. I'm quite new to rust and this is something I have never seen before :) – tzwickl Sep 01 '19 at 21:41

1 Answers1

1

In C, a struct whose last field is an array with no specified size is a dynamically typed struct. The data is present at the end of the struct with no extra level of indirection.

The Rust equivalent isn't a pointer (which has a fixed size), but a slice. Your struct would be in Rust:

#[allow(non_camel_case_types)]
#[repr(C)]
struct vfio_irq_set {
    argsz: u32,
    flags: u32,
    index: u32,
    start: u32,
    count: u32,
    data: [u8],
}

However those types are not really usable right now, and a more practical equivalent would be:

#[allow(non_camel_case_types)]
#[repr(C)]
struct vfio_irq_set<T: ?Sized> {
    argsz: u32,
    flags: u32,
    index: u32,
    start: u32,
    count: u32,
    data: T,
}

where you have to make sure that T is a properly sized array or slice.

See also:

mcarton
  • 27,633
  • 5
  • 85
  • 95
  • What do you think about [this question](https://stackoverflow.com/questions/51005645/how-to-implement-the-c-flexible-array-member-pattern-in-rust)? It does not have an answer yet. Do you think this question should be closed as a dupe? Do you want to move your answer then? What about the comments of the linked question: are they up to date yet? – Lukas Kalbertodt Sep 01 '19 at 21:27
  • 1
    @LukasKalbertodt you seem to be right. I answered the other question, although I can't make this one as duplicate yet at my answer hasn't been upvoted. – mcarton Sep 01 '19 at 21:38
  • @mcarton Thank you so much for your reply this worked :) I searched for almost 2 hours but didn't find the other one so sorry to asked a duplicate here :) – tzwickl Sep 01 '19 at 21:39
  • 1
    @tzwickl Don't worry about asking duplicates! It's always useful to have a few other questions with different formulations that link to the original one. That way, people can find the original answer more easily. – Lukas Kalbertodt Sep 01 '19 at 21:58