动态大小类型如何安全地表达?

时间:2019-04-02 05:03:05

标签: winapi rust ffi

我正在使用动态大小类型的FFI库编写安全的包装,并且我试图确定在Rust中处理它们的最佳方法。

特别是,我包装了Windows API的SID结构。它有一个BYTE(u8)指示当前版本,一个BYTE(u8)指示子授权机构的数量,六个BYTE([u8; 6])指示标识符授权,然后有一个一系列DWORD(u32),代表子机构的数量。它具有的子机构数与子机构数相同。

通常,方法是只通过WinAPI调用来处理SID,所以我应该永远只有一个指向它的指针。此外,通过将内部部件保密,我可以确保我的板条箱的消费者只能通过我控制的引用Box等访问它。但是,我确实需要声明某种Sid类型的 类型,并且我正在尝试确定最佳方法。

选项1:winapi的板条箱只是假设只会有a single sub-authority

pub struct SID {
    Revision: BYTE,
    SubAuthorityCount: BYTE,
    IdentifierAuthority: SID_IDENTIFIER_AUTHORITY, // [u8; 6]
    SubAuthority: [DWORD; 1],
}

仅在引用时有效,但是如果创建了拥有的Sid并将SubAuthorityCount设置为1以外的任何值,则WinAPI调用将读取无效的SubAuthority条目

选项2:乐观地分配DWORD的最大数量:

pub struct SID {
    Revision: BYTE,
    SubAuthorityCount: BYTE,
    IdentifierAuthority: SID_IDENTIFIER_AUTHORITY, // [u8; 6]
    SubAuthority: [DWORD; 256],
}

这会引入内存开销(常见的情况是有两个子权限)。这也意味着不能将WinAPI分配的SID强制转换为SID类型,因为Rust期望存在的附加SubAuthorities不是由SID分配的。

选项3:动态大小的数组:

pub struct SID {
    Revision: BYTE,
    SubAuthorityCount: BYTE,
    IdentifierAuthority: SID_IDENTIFIER_AUTHORITY, // [u8; 6]
    SubAuthority: [DWORD],
}

现在不再是Sized,它可以准确反映基础内存的形状。另外,由于Sized类型不能直接声明(我认为吗?),因此只能使用FFI调用来创建它。但是,现在所有指向它的指针都将自动变为胖指针,这使得与FFI调用进行互操作变得更加困难,而FFI调用都希望使用裸(细)指针。

选项4:永远不会分配它,所以……什么也没有。它将仅作为参考来处理,并且我将永远不会研究基础字段,因此完全没有理由公开任何内容:

pub struct SID {}

这感觉超级奇怪。我知道零大小类型在Rust中的行为与在C中不同,并且在FFI调用周围使用它们感到不舒服。但是,它的确反映了SID类型应该使用的方式:它只能通过引用(或Box或其他指针)使用,并且这些字段无关。但是,例如在将ZST &强制转换为原始指针然后返回时,我绝对不确定行为。

或者还有别的吗?目前,我正在使用选项1,将所有内容设为私有,只是不直接访问任何字段(所有内容都通过WinAPI调用),但我对人们推荐的方法以及我的分析是否正确感到好奇。

0 个答案:

没有答案