rust-lang / rust-lang/rust-bindgen

Opaque type should not have `pub` member

Open
#3,097 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
5.3k
Forks
829
Avg merge
1d 1h
Merged PRs (30d)
15

Description

For a type that is explicitly marked opaque via .opaque_type("Foo"), bindgen generates a type with a public member:

#[repr(C)]
#[repr(align(4))]
#[derive(Debug, Default, Copy, Clone)]
pub struct BAR__ {
    pub _bindgen_opaque_blob: u32,
}

Shouldn't _bindgen_opaque_blob be generated without pub? Making it pub allows the user to directly instantiate an instance of BAR__ which is most likely invalid, which defeats the purpose of it being an opaque type

Other Information
rust-bindgen 0.71.1
clang version 19.1.7
Target: x86_64-pc-windows-msvc

Full Code Sample
build.rs:

use std::env;
use std::path::PathBuf;

fn main() {
    tracing_subscriber::fmt::init();

    let builder = bindgen::Builder::default()
        .header_contents(
            "input.h",
            r#"
struct Foo;

struct BAR__{int unused;};
typedef struct BAR__ *BAR;
"#,
        )
        .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
        .derive_default(true);

    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());

    builder
        .clone()
        .generate()
        .expect("Unable to generate bindings")
        .write_to_file((out_path).join("not-explicit-opaque.rs"))
        .expect("Couldn't write bindings!");

    builder
        .opaque_type("Foo")
        .opaque_type("BAR__") // Only BAR__ should be marked as opaque. The convenience type BAR should remain as a pointer to the opaque BAR__. 
        .generate()
        .expect("Unable to generate bindings")
        .write_to_file((out_path).join("explicit-opaque.rs"))
        .expect("Couldn't write bindings!");
}

Output:
not-explicit-opaque.rs:

/* automatically generated by rust-bindgen 0.71.1 */

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Foo {
    _unused: [u8; 0],
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct BAR__ {
    pub unused: ::std::os::raw::c_int,
}
#[allow(clippy::unnecessary_operation, clippy::identity_op)]
const _: () = {
    ["Size of BAR__"][::std::mem::size_of::<BAR__>() - 4usize];
    ["Alignment of BAR__"][::std::mem::align_of::<BAR__>() - 4usize];
    ["Offset of field: BAR__::unused"][::std::mem::offset_of!(BAR__, unused) - 0usize];
};
pub type BAR = *mut BAR__;

explicit-opaque.rs:

/* automatically generated by rust-bindgen 0.71.1 */

#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct Foo {
    _unused: [u8; 0],
}
#[repr(C)]
#[repr(align(4))]
#[derive(Debug, Default, Copy, Clone)]
pub struct BAR__ {
    pub _bindgen_opaque_blob: u32,
}
#[allow(clippy::unnecessary_operation, clippy::identity_op)]
const _: () = {
    ["Size of BAR__"][::std::mem::size_of::<BAR__>() - 4usize];
    ["Alignment of BAR__"][::std::mem::align_of::<BAR__>() - 4usize];
};
pub type BAR = *mut BAR__;

Output Diff (left is no explicit opaque. right is explicit opaque):
Image

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the bindgen Builder configuration in build.rs and the .opaque_type("BAR__") path; compare explicit-opaque.rs with not-explicit-opaque.rs. Find or add a regression test for generated opaque fields, and verify that the generated blob cannot be directly instantiated while BAR remains a pointer to BAR__.

Written by the indexing model from the issue text.

Assessment

Tech stack
c, rust
Domain
compilers, devtools
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.