rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
96.64k stars 12.49k forks source link

trying to get pointer to extern typed field causes runtime panic #126800

Open lolbinarycat opened 2 months ago

lolbinarycat commented 2 months ago

I tried this code:

#![feature(extern_types)]
extern {
    type Opaque;
}

struct Thing {
    _pad: u8,
    o: Opaque,
}

fn main() {
    let v = b"a";
    let x: &Thing = unsafe { std::mem::transmute(&v) };
    let field_ptr = &x.o as *const Opaque;
    println!("{:X}", field_ptr as usize)
}

I expected to see this happen: printing a stack address

Instead, this happened: panic: attempted to compute the size or alignment of extern type

Context

one of the main usecases for extern types is representing trailing fields of variable size for C ffi. this bug completely makes this impossible. it also panics during a piece of safe code that should be infallible. this panic does not occur if the extern type is the only field.

Meta

rustc --version --verbose:

rustc 1.80.0-nightly (debd22da6 2024-05-29)
binary: rustc
commit-hash: debd22da66cfa97c74040ebf68e420672ac8560e
commit-date: 2024-05-29
host: x86_64-unknown-linux-gnu
release: 1.80.0-nightly
LLVM version: 18.1.6
Backtrace

``` Compiling playground v0.0.1 (/playground) Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.48s Running `target/debug/playground` thread 'main' panicked at library/core/src/panicking.rs:221:5: attempted to compute the size or alignment of extern type `Opaque` stack backtrace: 0: rust_begin_unwind at /rustc/684b3553f70148ded97a80371c2405984d4f6aa7/library/std/src/panicking.rs:661:5 1: core::panicking::panic_nounwind_fmt::runtime at /rustc/684b3553f70148ded97a80371c2405984d4f6aa7/library/core/src/panicking.rs:112:18 2: core::panicking::panic_nounwind_fmt at /rustc/684b3553f70148ded97a80371c2405984d4f6aa7/library/core/src/panicking.rs:122:5 3: core::panicking::panic_nounwind at /rustc/684b3553f70148ded97a80371c2405984d4f6aa7/library/core/src/panicking.rs:221:5 4: playground::main at ./[src/main.rs:14](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#):21 5: core::ops::function::FnOnce::call_once at /rustc/684b3553f70148ded97a80371c2405984d4f6aa7/library/core/src/ops/function.rs:250:5 note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. thread caused non-unwinding panic. aborting. ```

saethlin commented 2 months ago

The code you want cannot be allowed because the offset of the extern type field depends on the alignment of the extern type, which is unknowable.

lolbinarycat commented 2 months ago

hmm, this is an odd situation. it does seem like this should be impossible, since the alignment cannot be known, but it is also one of the primary usecases laid out in the RFC (see the OpaqueTail example).

perhaps there should be some way to explicitly "opt in" to the extern type having a known alignment (maybe just by using #[align]?)

lolbinarycat commented 2 months ago

behavior of trailing extern type fields should be added to the list of unresolved questions in the tracking issue https://github.com/rust-lang/rust/issues/43467

saethlin commented 2 months ago

You can feel free to comment on the tracking issue, but the behavior you are observing here is very intentional and not a bug in the implementation. We even have a test that the above code pattern panics: https://github.com/rust-lang/rust/blob/c1b336cb6b491b3be02cd821774f03af4992f413/tests/ui/extern/extern-types-field-offset.rs

lolbinarycat commented 2 months ago

then i would contend that the RFC was merged before it was ready, since it contains contradictory examples. indeed, the "Detailed Design" section does not contain many details at all.

Wasabi375 commented 2 months ago

I get an similar error when I use repr(packed) and addr_of!(x.o):

attempted to compute the size or alignment of extern type Opaque

Correct me if I'm wrong, but packed implies that the alignment is ignored. So in this case it should not be required to get a pointer.