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

Dubious improper_ctypes firing on recursive non-local containment? #116831

Closed
workingjubilee opened this issue Oct 17, 2023 · 2 comments · Fixed by #116863
Closed

Dubious improper_ctypes firing on recursive non-local containment? #116831

workingjubilee opened this issue Oct 17, 2023 · 2 comments · Fixed by #116863
Labels
A-FFI Area: Foreign function interface (FFI) A-lint Area: Lints (warnings about flaws in source code) such as unused_mut. C-bug Category: This is a bug. L-improper_ctypes Lint: improper_ctypes T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@workingjubilee
Copy link
Member

workingjubilee commented Oct 17, 2023

Bindgen allows you to create a "rustified non-exhaustive enum" from a C enum. This is used by pgrx-pg-sys for a specific C enum, NodeTag, because

  • NodeTag has a well-defined, finite list of variants for each major version
  • Despite this, much like a repr(Rust) enum, it regularly changes the assigned values to its variants each version, requiring an extension to be built against a specific Postgres version.
  • Each major version consistently adds at least one variant somewhere.
  • ...except for a zero-initialized value, which is always the sentinel value.
  • ...so it is much better, in terms of ergonomics, to treat it as a Rust-ish enum with an appropriate repr to make sure it is the correct size, with #[non_exhaustive], so that people can write the same code and have it be robust against future Postgres versions (though I seriously doubt anyone is going to write a 400 variant match, but hey, we've seen weirder, sooo...).

Unfortunately, it seems this can trigger the improper_ctypes lint if people add their own bindings against Postgres which mention pgrx_pg_sys's bound types, which they did not define the original bindings to, and which only recursively contains the improper ctype... i.e. they mentioned a pgrx-pg-sys-bound type, which is itself a pointer to a pgrx-pg-sys-bound type, that contains a pointer to another pgrx-pg-sys-bound type that itself contains the pgrx-pg-sys-bound enum.

Naturally, they have no idea what the hell is going on, since the error doesn't even mention which field is the offender, or how recursively deep it is.

This disappears if I make it a "rustified enum" instead, which lacks #[non_exhaustive]. It seems some reasoning is being applied along the lines of, "Non-exhaustive means that it can become FFI-incompatible in the future due to feature(arbitrary_enum_discriminant) and feature(really_tagged_unions), without breaking compat", when that has nothing to do with reality, and in fact I'm more trying to use it to encourage people to handle the C code correctly! And even if that was the case, the lint appears to be violating locality.

I tried this code:

use pgrx::pg_sys;

//  Many
//  lines
//  of
//  boiler-
//  plate 
//  code.

extern "C" {
    pub fn rdb_read_page(
        index: pg_sys::Relation,
        blkno: u32,
        lock_type: ::std::os::raw::c_int,
        pg_buffer: *mut u32,
    ) -> *mut ::std::os::raw::c_char;
}

I got this:

warning: `extern` block uses type `NodeTag`, which is not FFI-safe
  --> src/lib.rs:39:16
   |
39 |         index: pg_sys::Relation,
   |                ^^^^^^^^^^^^^^^^ not FFI-safe
   |
   = note: this enum is non-exhaustive
   = note: `#[warn(improper_ctypes)]` on by default

warning: `sample` (lib) generated 1 warning
    Finished dev [unoptimized + debuginfo] target(s) in 17.63s

I expected to not see a warning on types that weren't defined in the local crate, are de facto safe as argument types, and in any case are behind at least two pointers.

Meta

This repros on both stable and this nightly:

rustc --version --verbose:

rustc 1.75.0-nightly (fcab24817 2023-10-13)
binary: rustc
commit-hash: fcab24817c72ffbd6ffb66d92b7ddc0d3ee4d2f0
commit-date: 2023-10-13
host: x86_64-unknown-linux-gnu
release: 1.75.0-nightly
LLVM version: 17.0.2
@workingjubilee workingjubilee added A-lint Area: Lints (warnings about flaws in source code) such as unused_mut. A-FFI Area: Foreign function interface (FFI) C-bug Category: This is a bug. labels Oct 17, 2023
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Oct 17, 2023
@workingjubilee workingjubilee added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Oct 17, 2023
@workingjubilee workingjubilee added the T-lang Relevant to the language team, which will review and decide on the PR/issue. label Oct 17, 2023
@workingjubilee
Copy link
Member Author

This was apparently decided thus by T-lang #44109 (comment) but I do not think that T-lang's reasoning holds up in the face of actual software composition and usage patterns.

@workingjubilee
Copy link
Member Author

workingjubilee commented Oct 17, 2023

I should also note that removing non_exhaustive is actually really bad in my use-case: I need the non_exhaustive quality on the enum so programmers can't cast the enum to a random integer. People reaching for pgrx are often new to Rust, used to C, and thus will be flailing a bit, and if they start casting it to integers, they're about to shoot themselves in the foot if they make a comparison to integer literals, because it's not a stable value. This is the other half of why I wanted it as an enum.

@workingjubilee workingjubilee removed the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Oct 20, 2023
@jieyouxu jieyouxu added the L-improper_ctypes Lint: improper_ctypes label May 13, 2024
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Oct 19, 2024
…ot-ffi-unsafe, r=jieyouxu

warn less about non-exhaustive in ffi

Bindgen allows generating `#[non_exhaustive] #[repr(u32)]` enums. This results in nonintuitive nonlocal `improper_ctypes` warnings, even when the types are otherwise perfectly valid in C.

Adjust for actual tooling expectations by avoiding warning on simple enums with only unit variants.

Closes rust-lang#116831
@bors bors closed this as completed in b2d132f Oct 20, 2024
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Oct 20, 2024
Rollup merge of rust-lang#116863 - workingjubilee:non-exhaustive-is-not-ffi-unsafe, r=jieyouxu

warn less about non-exhaustive in ffi

Bindgen allows generating `#[non_exhaustive] #[repr(u32)]` enums. This results in nonintuitive nonlocal `improper_ctypes` warnings, even when the types are otherwise perfectly valid in C.

Adjust for actual tooling expectations by avoiding warning on simple enums with only unit variants.

Closes rust-lang#116831
tgross35 added a commit to tgross35/rust that referenced this issue Nov 5, 2024
…ler-errors

More tests for non-exhaustive C-like enums in FFI

Add a few more tests for the `improper_ctypes` lint as found with the [varnish-rs](https://github.com/gquintard/varnish-rs) project.

This follows up on rust-lang#116831, fixed in rust-lang#116863 by `@workingjubilee` - I have been seeing these fail with the bindgen-generated non-exhaustive enums inside other structs. Seems the issue does not exist in the primary branch, so this PR just makes sure more cases are covered for the future.
workingjubilee added a commit to workingjubilee/rustc that referenced this issue Nov 5, 2024
…ler-errors

More tests for non-exhaustive C-like enums in FFI

Add a few more tests for the `improper_ctypes` lint as found with the [varnish-rs](https://github.com/gquintard/varnish-rs) project.

This follows up on rust-lang#116831, fixed in rust-lang#116863 by ``@workingjubilee`` - I have been seeing these fail with the bindgen-generated non-exhaustive enums inside other structs. Seems the issue does not exist in the primary branch, so this PR just makes sure more cases are covered for the future.
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Nov 5, 2024
Rollup merge of rust-lang#132303 - nyurik:non-exhaustive-err, r=compiler-errors

More tests for non-exhaustive C-like enums in FFI

Add a few more tests for the `improper_ctypes` lint as found with the [varnish-rs](https://github.com/gquintard/varnish-rs) project.

This follows up on rust-lang#116831, fixed in rust-lang#116863 by ``@workingjubilee`` - I have been seeing these fail with the bindgen-generated non-exhaustive enums inside other structs. Seems the issue does not exist in the primary branch, so this PR just makes sure more cases are covered for the future.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-FFI Area: Foreign function interface (FFI) A-lint Area: Lints (warnings about flaws in source code) such as unused_mut. C-bug Category: This is a bug. L-improper_ctypes Lint: improper_ctypes T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants