Skip to content

Make the Pod/NoUninit derive macros not use transmute, to be more robust against possible future relaxations transmute's size check. #320

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

Merged

Conversation

zachs18
Copy link
Contributor

@zachs18 zachs18 commented Aug 4, 2025

RFC 3844 is proposing relaxations to std::mem::transmute's semantics, and under some possible relaxations, bytemuck_derive's current usage of it to ensure soundness becomes insufficient1.

This PR makes the Pod/NoUninit derive not use transmute, and instead emit a const _: () = assert! that ensures there is no padding in the type by asserting that the type's size is the same as the sum of the type's fields' sizes.

Concrete change: For the following source code:

use bytemuck::*;

#[derive(Debug, Clone, Copy, NoUninit)]
#[repr(C)]
struct Foo(u32, u16);

The Pod derive macros' no-padding check is changed from:

// expansion
const _: fn() = || {
    #[doc(hidden)]
    struct TypeWithoutPadding(
        [u8; ::core::mem::size_of::<u32>() + ::core::mem::size_of::<u16>()],
    );
    let _ = ::core::mem::transmute::<Foo, TypeWithoutPadding>;
};

// error
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
 --> src/lib.rs:3:40
  |
3 | #[derive(Debug, Clone, Copy, Zeroable, Pod)]
  |                                        ^^^
  |
  = note: source type: `Foo` (64 bits)
  = note: target type: `_::{closure#0}::TypeWithoutPadding` (48 bits)
  = note: this error originates in the derive macro `Pod` (in Nightly builds, run with -Z macro-backtrace for more info)

To this:

// expansion
const _: () = {
    assert!(
        ::core::mem::size_of::<Foo>() == (::core::mem::size_of::<u32>() + ::core::mem::size_of::<u16>()),
        "derive(Pod) was applied to a type with padding",
    );
};


// error
error[E0080]: evaluation of constant value failed
 --> src/lib.rs:3:40
  |
3 | #[derive(Debug, Clone, Copy, Zeroable, Pod)]
  |                                        ^^^ evaluation panicked: derive(Pod) was applied to a type with padding

(derive(NoUninit) is the same, but the assert message mentions NoUninit instead of Pod)

Footnotes

  1. Currently, the derive macros only mention std::mem::transmute::<Foo, FooWithoutPadding>, they don't call it, and under at least the proposed "just have a const assert that the sizes are the same in the body of transmute" change, this would no longer be enough to ensure a compiler error if Type1 and Type2 have different sizes: playground link

@Lokathor
Copy link
Owner

Lokathor commented Aug 4, 2025

I think we should make it be a const eval error using a const block. Regardless of the string formatting being unavailable, it's the "most correct" check to perform, and if transmute isn't doing it implicitly then we should keep doing it ourselves explicitly.

@zachs18 zachs18 force-pushed the forward-compat-with-transmute-relaxation branch from 7a1a32c to 8a787ae Compare August 6, 2025 03:54
@zachs18 zachs18 changed the title Make the Pod/NoUninit derive macros more robust against possible future relaxations of std::mem::transmute's semantics. Make the Pod/NoUninit derive macros not use transmute, to be more robust against possible future relaxations transmute's size check. Aug 6, 2025
@zachs18
Copy link
Contributor Author

zachs18 commented Aug 6, 2025

Latest push makes the derive macros emit a const assert instead of using transmute at all.

@Lokathor
Copy link
Owner

Lokathor commented Aug 6, 2025

Seems good, so we should merge and publish as is, or is there more to do?

@zachs18
Copy link
Contributor Author

zachs18 commented Aug 6, 2025

I don't think there's anything else needed here; this should be good to publish

@Lokathor Lokathor merged commit 374df78 into Lokathor:main Aug 6, 2025
14 checks passed
@Lokathor Lokathor added semver-patch semver patch change proc-macros I don't do proc-macros, but I accepts PRs about them. labels Aug 6, 2025
@Lokathor
Copy link
Owner

Lokathor commented Aug 6, 2025

Published 1.10.1 of the derives

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
proc-macros I don't do proc-macros, but I accepts PRs about them. semver-patch semver patch change
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants