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

Document that #[derive(IntoBytes)] only supports unsized types which are repr(packed) #1566

Closed
Tracked by #671
njsmith opened this issue Aug 4, 2024 · 5 comments
Closed
Tracked by #671
Labels
blocking-next-release This issue should be resolved before we release on crates.io

Comments

@njsmith
Copy link

njsmith commented Aug 4, 2024

Update (authored by @joshlf)

See #1566 (comment).

This issue tracks improving the documentation on either IntoBytes or the re-export of zerocopy_derive::IntoBytes to document that #[derive(IntoBytes)] does not support unsized types unless those types are also repr(packed).

Original issue text

Original title: Can't #[derive(IntoBytes)] on a slice DST?

I'm experimenting with the current main branch (1ff83c4) and its support for slice DSTs. I wrote:

// This is a dynamically sized type
#[derive(Debug, FromBytes, IntoBytes, KnownLayout, Immutable)]
#[repr(C)]
pub struct StatsReport {
    written: U64,
    values: [U64],
}

As far as I can tell from the docs, this should be supported in this branch?

But it errors out with:

error[E0277]: the size for values of type `[U64<zerocopy::BigEndian>]` cannot be known at compilation time
  --> [...]/stats.rs:21:12
   |
21 | pub struct StatsReport {
   |            ^^^^^^^^^^^ doesn't have a size known at compile-time
   |
   = help: within `StatsReport`, the trait `Sized` is not implemented for `[U64<zerocopy::BigEndian>]`, which is required by `StatsReport: Sized`
note: required because it appears within the type `StatsReport`
  --> [...]/stats.rs:21:12
   |
21 | pub struct StatsReport {
   |            ^^^^^^^^^^^
note: required by a bound in `std::mem::size_of`
  --> /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library/core/src/mem/mod.rs:312:1

error[E0277]: the size for values of type `[U64<zerocopy::BigEndian>]` cannot be known at compilation time
  --> [...]/stats.rs:23:13
   |
23 |     values: [U64],
   |             ^^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `Sized` is not implemented for `[U64<zerocopy::BigEndian>]`
note: required by a bound in `std::mem::size_of`
  --> /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library/core/src/mem/mod.rs:312:1

For more information about this error, try `rustc --explain E0277`.

The error message is annoyingly uncommunicative about what's going on, but the problem seems to be the #[derive(IntoBytes)], where cargo expand shows that zerocopy is generating this code:

    unsafe impl ::zerocopy::IntoBytes for StatsReport
    where
        U64: ::zerocopy::IntoBytes,
        [U64]: ::zerocopy::IntoBytes,
        ::zerocopy::macro_util::HasPadding<
            StatsReport,
            {
                ::zerocopy::macro_util::core_reexport::mem::size_of::<StatsReport>()
                    > 0 + ::zerocopy::macro_util::core_reexport::mem::size_of::<U64>()
                        + ::zerocopy::macro_util::core_reexport::mem::size_of::<[U64]>()
            },
        >: ::zerocopy::macro_util::ShouldBe<false>,

which yeah, doesn't seem like that could work.

I figure this might be any of:

  • a bug
  • not expected to work, docs should be clarified
  • chill out dude, this is unreleased and unfinished, we'll get there

...But figured I'd check.

@njsmith njsmith added the customer-request Documents customer requests. label Aug 4, 2024
@njsmith
Copy link
Author

njsmith commented Aug 4, 2024

Further experiment: changing the struct from repr(C) to repr(C, packed) seems to get past this error, even though in this case it doesn't affect the layout.

@joshlf
Copy link
Member

joshlf commented Aug 9, 2024

This is a limitation in IntoBytes - there's no way for us to determine that all possible instances of an unsized type will be free of padding unless that type is repr(packed). The docs should definitely be improved, though; I'll change this issue to track improving the docs.

See also: #1112

@joshlf joshlf changed the title Can't #[derive(IntoBytes)] on a slice DST? Document that #[derive(IntoBytes)] only supports unsized types which are repr(packed) Aug 9, 2024
@joshlf joshlf mentioned this issue Aug 9, 2024
81 tasks
@joshlf joshlf added blocking-next-release This issue should be resolved before we release on crates.io and removed customer-request Documents customer requests. labels Aug 9, 2024
@jswrenn
Copy link
Collaborator

jswrenn commented Aug 9, 2024

@joshlf, given the syntactic absence of repr(packed), could we emit a Self: Unaligned or TrailingField: Unaligned bound to support this case?

@joshlf
Copy link
Member

joshlf commented Aug 9, 2024

@joshlf, given the syntactic absence of repr(packed), could we emit a Self: Unaligned or TrailingField: Unaligned bound to support this case?

Unfortunately I don't think that works for a few reasons:

  • We'd need to be able to determine that a type is unsized. We can't do that syntactically (e.g. the field could be a type alias to a slice type, which we can't observe), and it's not always a property of the type itself (e.g., #[repr(C)] struct Foo<T>(T) is only unsized when T is).
  • Self: Unaligned would be sufficient, but TrailingField: Unaligned would not be (e.g. #[repr(C)] struct Bar(u16, [u8]))

Also, there are other cases we'd ideally like to support (like the one mentioned in this issue) where the type has a non-trivial alignment requirement (so Self: Unaligned wouldn't be satisfied), and yet is guaranteed not to have padding; it'd be weird if we supported this use case on piecemeal in a way that would be very opaque and confusing to users.

@joshlf
Copy link
Member

joshlf commented Sep 7, 2024

Fixed by #1616

@joshlf joshlf closed this as completed Sep 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
blocking-next-release This issue should be resolved before we release on crates.io
Projects
None yet
Development

No branches or pull requests

3 participants