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

Safe Transmute: Require that source referent is smaller than destination #122438

Merged
merged 1 commit into from Mar 14, 2024

Conversation

jswrenn
Copy link
Member

@jswrenn jswrenn commented Mar 13, 2024

BikeshedIntrinsicFrom currently models transmute-via-union; i.e., it attempts to provide a where bound for this function:

pub unsafe fn transmute_via_union<Src, Dst>(src: Src) -> Dst {
    use core::mem::*;

    #[repr(C)]
    union Transmute<T, U> {
        src: ManuallyDrop<T>,
        dst: ManuallyDrop<U>,
    }

    let transmute = Transmute { src: ManuallyDrop::new(src) };

    // SAFETY: The caller must guarantee that the transmutation is safe.
    let dst = transmute.dst;

    ManuallyDrop::into_inner(dst)
}

A quirk of this model is that it admits padding extensions in value-to-value transmutation: The destination type can be bigger than the source type, so long as the excess consists of uninitialized bytes. However, this isn't permissible for reference-to-reference transmutations (introduced in #110662) — extra referent bytes cannot come from thin air.

This PR patches our analysis for reference-to-reference transmutations to require that the destination referent is no larger than the source referent.

r? @compiler-errors

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Mar 13, 2024
Comment on lines 269 to 273
} else if dst_ref.size() > src_ref.size() {
Answer::No(Reason::DstRefIsTooBig {
src: src_ref,
dst: src_ref,
})
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(This is the critical change of the PR.)

@@ -81,6 +92,16 @@ pub mod rustc {
}
impl<'tcx> Ref<'tcx> {}

impl<'tcx> fmt::Display for Ref<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_char('&')?;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not printing the region here too?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could, but it's not relevant to the error message this Display routine is currently used in, and I don't anticipate it will be relevant to other transmute error messages, since regions do not impact layout.

let src_size = src.size;
let dst_size = dst.size;
format!(
"The referent size of `{src}` ({src_size} bytes) is smaller than that of `{dst}` ({dst_size} bytes"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"The referent size of `{src}` ({src_size} bytes) is smaller than that of `{dst}` ({dst_size} bytes"
"The referent size of `{src}` ({src_size} bytes) is smaller than that of `{dst}` ({dst_size} bytes)"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Mar 13, 2024
--> $DIR/unit-to-u8.rs:22:52
|
LL | assert::is_maybe_transmutable::<&'static Unit, &'static u8>();
| ^^^^^^^^^^^ The size of `Unit` is smaller than the size of `u8`
| ^^^^^^^^^^^ The referent size of `&Unit` (0 bytes) is smaller than that of `&Unit` (0) bytes
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still doesn't look right 😆

Suggested change
| ^^^^^^^^^^^ The referent size of `&Unit` (0 bytes) is smaller than that of `&Unit` (0) bytes
| ^^^^^^^^^^^ The referent size of `&Unit` (0 bytes) is smaller than that of `&Unit` (0 bytes)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oof, I need to sleep more.

Done?

Copy link
Member

@compiler-errors compiler-errors left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please triple check the error messages.

} else if dst_ref.size() > src_ref.size() {
Answer::No(Reason::DstRefIsTooBig {
src: src_ref,
dst: src_ref,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
dst: src_ref,
dst: dst_ref,

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

The source referent absolutely must be smaller than the destination
referent of a ref-to-ref transmute; the excess bytes referenced
cannot arise from thin air, even if those bytes are uninitialized.
error[E0277]: `&Packed<Two>` cannot be safely transmuted into `&Packed<Four>`
--> $DIR/reject_extension.rs:48:37
|
LL | assert::is_transmutable::<&Src, &Dst>();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like that only the second parameter is ^^^^, but that's a general issue with all of our error messages that I'll file a follow-up PR for.

Otherwise, this error message LGTM.

@compiler-errors
Copy link
Member

@bors r+ rollup

@bors
Copy link
Contributor

bors commented Mar 13, 2024

📌 Commit 216df4a has been approved by compiler-errors

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Mar 13, 2024
bors added a commit to rust-lang-ci/rust that referenced this pull request Mar 13, 2024
…iaskrgr

Rollup of 11 pull requests

Successful merges:

 - rust-lang#122422 (compiletest: Allow `only-unix` in test headers)
 - rust-lang#122424 (fix: typos)
 - rust-lang#122425 (Increase timeout for new bors bot)
 - rust-lang#122426 (Fix StableMIR `WrappingRange::is_full` computation)
 - rust-lang#122429 (Add Exploit Mitigations PG to triagebot.toml)
 - rust-lang#122430 (Generate link to `Local` in `hir::Let` documentation)
 - rust-lang#122434 (pattern analysis: rename a few types)
 - rust-lang#122437 (pattern analysis: remove `MaybeInfiniteInt::JustAfterMax`)
 - rust-lang#122438 (Safe Transmute: Require that source referent is smaller than destination)
 - rust-lang#122442 (extend docs of -Zprint-mono-items)
 - rust-lang#122449 (Delay a bug for stranded opaques)

r? `@ghost`
`@rustbot` modify labels: rollup
bors added a commit to rust-lang-ci/rust that referenced this pull request Mar 14, 2024
…iaskrgr

Rollup of 11 pull requests

Successful merges:

 - rust-lang#122422 (compiletest: Allow `only-unix` in test headers)
 - rust-lang#122424 (fix: typos)
 - rust-lang#122425 (Increase timeout for new bors bot)
 - rust-lang#122426 (Fix StableMIR `WrappingRange::is_full` computation)
 - rust-lang#122429 (Add Exploit Mitigations PG to triagebot.toml)
 - rust-lang#122430 (Generate link to `Local` in `hir::Let` documentation)
 - rust-lang#122434 (pattern analysis: rename a few types)
 - rust-lang#122437 (pattern analysis: remove `MaybeInfiniteInt::JustAfterMax`)
 - rust-lang#122438 (Safe Transmute: Require that source referent is smaller than destination)
 - rust-lang#122442 (extend docs of -Zprint-mono-items)
 - rust-lang#122449 (Delay a bug for stranded opaques)

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit 89c3fa9 into rust-lang:master Mar 14, 2024
11 checks passed
@rustbot rustbot added this to the 1.78.0 milestone Mar 14, 2024
rust-timer added a commit to rust-lang-ci/rust that referenced this pull request Mar 14, 2024
Rollup merge of rust-lang#122438 - jswrenn:check-referent-size, r=compiler-errors

Safe Transmute: Require that source referent is smaller than destination

`BikeshedIntrinsicFrom` currently models transmute-via-union; i.e., it attempts to provide a `where` bound for this function:
```rust
pub unsafe fn transmute_via_union<Src, Dst>(src: Src) -> Dst {
    use core::mem::*;

    #[repr(C)]
    union Transmute<T, U> {
        src: ManuallyDrop<T>,
        dst: ManuallyDrop<U>,
    }

    let transmute = Transmute { src: ManuallyDrop::new(src) };

    // SAFETY: The caller must guarantee that the transmutation is safe.
    let dst = transmute.dst;

    ManuallyDrop::into_inner(dst)
}
```
A quirk of this model is that it admits padding extensions in value-to-value transmutation: The destination type can be bigger than the source type, so long as the excess consists of uninitialized bytes. However, this isn't permissible for reference-to-reference transmutations (introduced in rust-lang#110662) — extra referent bytes cannot come from thin air.

This PR patches our analysis for reference-to-reference transmutations to require that the destination referent is no larger than the source referent.

r? `@compiler-errors`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants