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

False positives from invalid_reference_casting #124685

Closed
khuey opened this issue May 4, 2024 · 6 comments · Fixed by #124761
Closed

False positives from invalid_reference_casting #124685

khuey opened this issue May 4, 2024 · 6 comments · Fixed by #124761
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-lints Area: Lints (warnings about flaws in source code) such as unused_mut. C-bug Category: This is a bug. D-papercut Diagnostics: An error or lint that needs small tweaks.

Comments

@khuey
Copy link
Contributor

khuey commented May 4, 2024

use std::ptr;

fn apply_mask(array: &mut [u8], offset: usize, mask: u64) {
    assert!(offset + 8 <= array.len());
    let a1 = &mut array[offset];
    let a2 = a1 as *mut u8;
    let a3 = a2 as *mut u64;
    unsafe {
        ptr::write_unaligned(a3, ptr::read_unaligned(a3) | mask);
    };
}

Starting with rustc 1.78.0 (because of #118983) this produces the following

error: casting references to a bigger memory layout than the backing allocation is undefined behavior, even if the reference is unused
 --> src/lib.rs:9:9
  |
5 |     let a1 = &mut array[offset];
  |                   ------------- backing allocation comes from here
6 |     let a2 = a1 as *mut u8;
7 |     let a3 = a2 as *mut u64;
  |              -------------- casting happend here
8 |     unsafe {
9 |         ptr::write_unaligned(a3, ptr::read_unaligned(a3) | mask);
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: casting from `u8` (1 bytes) to `u64` (8 bytes)
  = note: `#[deny(invalid_reference_casting)]` on by default

Perhaps I'm missing something but this is not undefined behavior as far as I can tell. The lint is wrong about the backing allocation and I suspect the false warning is downstream from that?

@khuey khuey added the C-bug Category: This is a bug. label May 4, 2024
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label May 4, 2024
@saethlin saethlin added A-lints Area: Lints (warnings about flaws in source code) such as unused_mut. regression-from-stable-to-stable Performance or correctness regression from one stable version to another. and removed needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. labels May 4, 2024
@rustbot rustbot added the I-prioritize Issue: Indicates that prioritization has been requested for this issue. label May 4, 2024
@asquared31415
Copy link
Contributor

asquared31415 commented May 4, 2024

Under the memory model checked by Miri by default, a &mut u8 is not permitted to access more than the one byte it points to, even if you got it from a larger object. Reborrowing to a reference type shrinks the allowed access range. Use array[offset..(offset + 8)].as_mut_ptr() instead to obtain a pointer that is valid to write to the correct region. array[offset..].as_mut_ptr() would also be valid, as that region contains the correct bytes, but it's less precise about its intent.

@rustbot label -regression-from-stable-to-stable -C-bug -I-prioritize +C-discussion

@rustbot rustbot added C-discussion Category: Discussion or questions that doesn't represent real issues. and removed regression-from-stable-to-stable Performance or correctness regression from one stable version to another. C-bug Category: This is a bug. I-prioritize Issue: Indicates that prioritization has been requested for this issue. labels May 4, 2024
@asquared31415
Copy link
Contributor

Miri also agrees that the code as written contains undefined behavior, in the top right of the page select "Tools > Miri" to run and you'll see that it says that there's undefined behavior.
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=e2d5ba429bbd2fb8401599c04d046213

The important bit from the error message is that the code is trying to access alloc1270[0x0..0x8] (the intended 8 bytes), but the pointer does not have permission for that range, only [0x0..0x1] (the first byte).

@asquared31415
Copy link
Contributor

I think that the invalid_reference_casting lint's wording should be changed though, "backing allocation" is not precise and does not correctly describe what it's detecting. cc #118983

@rustbot label +A-diagnostics +D-papercut

@rustbot rustbot added A-diagnostics Area: Messages for errors, warnings, and lints D-papercut Diagnostics: An error or lint that needs small tweaks. labels May 4, 2024
@saethlin
Copy link
Member

saethlin commented May 4, 2024

Under the current memory model,

Your comment and the lint are misleading. There is no accepted memory model. And the lint message is pointing to code which does not create an allocation, so at best the lint has grabbed the wrong span. If this lint is supposed to engage in provenance-based reasoning, it would need to indicate that. Otherwise it is simply buggy.

@asquared31415
Copy link
Contributor

True, "the current" is not quite right. "The memory model currently checked by Miri by default" is perhaps a better wording for what I wanted to say, I will edit my comment.

Agreed that the lint is definitely sketchy wording at best, and I'm suspicious of its implementation given the incorrect wording.

@saethlin saethlin added C-bug Category: This is a bug. and removed C-discussion Category: Discussion or questions that doesn't represent real issues. labels May 4, 2024
@saethlin saethlin changed the title False positive invalid_reference_casting? False positives from invalid_reference_casting May 4, 2024
@Urgau
Copy link
Member

Urgau commented May 4, 2024

And the lint message is pointing to code which does not create an allocation, so at best the lint has grabbed the wrong span. If this lint is supposed to engage in provenance-based reasoning, it would need to indicate that. Otherwise it is simply buggy.

The lint is not supposed to engage in "provenance-based reasoning", it is just supposed to peel all the reference/raw pointer casting until it finds an allocation, and then it should compare the size of type and report an error if the target is bigger than the source. Nothing else, nothing more.

I tried describing the intent of the change in #118983 (comment).

So as @saethlin correctly mentions it, nothing in this code creates an "allocation", so I think the lint shouldn't have fired here. (whenever there is actual UB or not is irrelevant here)

@bors bors closed this as completed in 9fce3dc May 8, 2024
rust-timer added a commit to rust-lang-ci/rust that referenced this issue May 8, 2024
Rollup merge of rust-lang#124761 - Urgau:ref-casting_bigger_slice_index, r=jieyouxu

Fix insufficient logic when searching for the underlying allocation

This PR fixes the logic inside the `invalid_reference_casting` lint, when trying to lint on bigger memory layout casts.

More specifically when looking for the "underlying allocation" we were wrongly assuming that when we got `&mut slice[index]` that `slice[index]` was the allocation, but it's not.

Fixes rust-lang#124685
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-lints Area: Lints (warnings about flaws in source code) such as unused_mut. C-bug Category: This is a bug. D-papercut Diagnostics: An error or lint that needs small tweaks.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants