Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incomplete types should generate enums with no variants #198

Closed
fitzgen opened this issue Nov 3, 2016 · 2 comments
Closed

Incomplete types should generate enums with no variants #198

fitzgen opened this issue Nov 3, 2016 · 2 comments

Comments

@fitzgen
Copy link
Member

fitzgen commented Nov 3, 2016

A common pattern is to declare structs/classes in a header, but leave their definition incomplete so that the public API consumers can't manipulate them directly and can only pass pointers/references to API functions that do the heavy lifting. Additionally, API consumers can't construct instances of these incomplete types, and rely on getting pointers to them from other public API functions.

Simple example:

struct MyDetailsArePrivate;

MyDetailsArePrivate* makeIt();
int publicApiGetter(MyDetailsArePrivate* details);

We currently generate Rust bindings like this (trimmed down for brevity):

#[repr(C)]
#[derive(Debug, Copy)]
pub struct MyDetailsArePrivate {
    pub _address: u8,
}

extern "C" {
    #[link_name = "_Z6makeItv"]
    pub fn makeIt() -> *mut MyDetailsArePrivate;
}
extern "C" {
    #[link_name = "_Z15publicApiGetterP19MyDetailsArePrivate"]
    pub fn publicApiGetter(details: *mut MyDetailsArePrivate)
     -> ::std::os::raw::c_int;
}

The way we generate a struct for MyDetailsArePrivate means that Rust users can construct instances. This is incorrect, and the false instances are almost assuredly the wrong size, and definitely will contain invalid data. This means that passing pointers to them into FFI functions would be wildly unsafe.

If instead we generated an enum without any variants, then it would be impossible to construct false instances in Rust, but the FFI functions that take and receive pointers to it would continue to work:

pub enum MyDetailsArePrivate {
}

extern "C" {
    #[link_name = "_Z6makeItv"]
    pub fn makeIt() -> *mut MyDetailsArePrivate;
}
extern "C" {
    #[link_name = "_Z15publicApiGetterP19MyDetailsArePrivate"]
    pub fn publicApiGetter(details: *mut MyDetailsArePrivate)
     -> ::std::os::raw::c_int;
}
@emilio
Copy link
Contributor

emilio commented Nov 3, 2016

Yup! This is sort of a duplicate of #62

@fitzgen
Copy link
Member Author

fitzgen commented Nov 3, 2016

Yup! This is sort of a duplicate of #62

Ah, so it is!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants