Skip to content

Consider improving accessibility of working with flexible array members in the windows crate #3172

Closed
@ChayimFriedman2

Description

@ChayimFriedman2

Suggestion

Many Windows APIs return flexible array members. Working with them in Rust is terrible. You must only use raw pointers, as references will invalidate access to the undeclared part of the array in Stacked Borrows (rust-lang/unsafe-code-guidelines#256), and it's easy to make mistakes and cause UB.

We can generate a simple wrapper type per FAM that can simplify working with them a lot. Something along the lines of:

// Assume the following simple struct:
#[repr(C)]
pub struct Fam {
    len: usize,
    other: u32,
    array: [i32; 1],
}

// We generate the following code:
#[repr(transparent)]
pub struct FamPtr(*mut Fam);

impl FamPtr {
    pub fn as_raw(&self) -> *mut Fam { self.0 }
    pub unsafe fn from_raw(raw: *mut Fam) -> Self { Self(raw) }
    
    pub fn len(&self) -> &usize {
        unsafe { &(*self.0).len }
    }
    // No `len_mut()`, that would be unsound.
    pub fn other(&self) -> &u32 {
        unsafe { &(*self.0).other }
    }
    pub fn other_mut(&mut self) -> &mut u32 {
        unsafe { &mut (*self.0).other }
    }
    
    pub fn array(&self) -> &[i32] {
        unsafe {
            core::slice::from_raw_parts(
                core::ptr::addr_of!((*self.0).array).cast::<i32>(),
                (*self.0).len,
            )
        }
    }
    pub fn array_mut(&mut self) -> &[i32] {
        unsafe {
            core::slice::from_raw_parts_mut(
                core::ptr::addr_of_mut!((*self.0).array).cast::<i32>(),
                (*self.0).len,
            )
        }
    }
}

There can be additional extensions (for example, supporting taking mutable references to many array members at the same time, safely allocating FAMs on the stack or the heap, or freeing them automatically) but even that alone is way better than the status quo.

Every function taking a pointer to a flexible struct will gain the ability to call it with its wrapper instead (probably with a trait).

I don't know if win32metadata marks flexible array members and their length field, so I don't know if this is possible, but if it is it can be a major improvement.

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionFurther information is requested

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions