diff options
| author | Ralf Jung <post@ralfj.de> | 2022-09-30 14:54:30 +0200 |
|---|---|---|
| committer | Ralf Jung <post@ralfj.de> | 2023-01-31 20:28:11 +0100 |
| commit | dfc4a7b2d02528f246e455f587605cce224bb99c (patch) | |
| tree | 36b96c1f46b9ce4d490eefaf4f77ac273595101c /compiler | |
| parent | f361413cbf44ce2f144df59fc440cd484af4a56e (diff) | |
| download | rust-dfc4a7b2d02528f246e455f587605cce224bb99c.tar.gz rust-dfc4a7b2d02528f246e455f587605cce224bb99c.zip | |
make unaligned_reference a hard error
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_error_codes/src/error_codes.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_error_codes/src/error_codes/E0793.md | 64 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/lib.rs | 11 | ||||
| -rw-r--r-- | compiler/rustc_lint_defs/src/builtin.rs | 46 | ||||
| -rw-r--r-- | compiler/rustc_mir_transform/src/check_packed_ref.rs | 43 |
5 files changed, 93 insertions, 74 deletions
diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 4ae372bb904..072b0f2fcce 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -5,7 +5,7 @@ // /!\ IMPORTANT /!\ // // Error messages' format must follow the RFC 1567 available here: -// https://github.com/rust-lang/rfcs/pull/1567 +// https://rust-lang.github.io/rfcs/1567-long-error-codes-explanation-normalization.html register_diagnostics! { E0001: include_str!("./error_codes/E0001.md"), @@ -510,6 +510,7 @@ E0789: include_str!("./error_codes/E0789.md"), E0790: include_str!("./error_codes/E0790.md"), E0791: include_str!("./error_codes/E0791.md"), E0792: include_str!("./error_codes/E0792.md"), +E0793: include_str!("./error_codes/E0793.md"), ; // E0006, // merged with E0005 // E0008, // cannot bind by-move into a pattern guard diff --git a/compiler/rustc_error_codes/src/error_codes/E0793.md b/compiler/rustc_error_codes/src/error_codes/E0793.md new file mode 100644 index 00000000000..b2e51e24e14 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0793.md @@ -0,0 +1,64 @@ +An unaligned references to a field of a [packed] struct got created. + +Erroneous code example: + +```compile_fail,E0793 +#[repr(packed)] +pub struct Foo { + field1: u64, + field2: u8, +} + +unsafe { + let foo = Foo { field1: 0, field2: 0 }; + // Accessing the field directly is fine. + let val = foo.field1; + // A reference to a packed field causes a error. + let val = &foo.field1; // ERROR + // An implicit `&` is added in format strings, causing the same error. + println!("{}", foo.field1); // ERROR +} +``` + +Creating a reference to an insufficiently aligned packed field is +[undefined behavior] and therefore disallowed. Using an `unsafe` block does not +change anything about this. Instead, the code should do a copy of the data in +the packed field or use raw pointers and unaligned accesses. + +``` +#[repr(packed)] +pub struct Foo { + field1: u64, + field2: u8, +} + +unsafe { + let foo = Foo { field1: 0, field2: 0 }; + + // Instead of a reference, we can create a raw pointer... + let ptr = std::ptr::addr_of!(foo.field1); + // ... and then (crucially!) access it in an explicitly unaligned way. + let val = unsafe { ptr.read_unaligned() }; + // This would *NOT* be correct: + // let val = unsafe { *ptr }; // Undefined Behavior due to unaligned load! + + // For formatting, we can create a copy to avoid the direct reference. + let copy = foo.field1; + println!("{}", copy); + // Creating a copy can be written in a single line with curly braces. + // (This is equivalent to the two lines above.) + println!("{}", { foo.field1 }); +} +``` + +### Additional information + +Note that this error is specifically about *references* to packed fields. +Direct by-value access of those fields is fine, since then the compiler has +enough information to generate the correct kind of access. + +See [issue #82523] for more information. + +[packed]: https://doc.rust-lang.org/reference/type-layout.html#the-alignment-modifiers +[undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html +[issue #82523]: https://github.com/rust-lang/rust/issues/82523 diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index ba15dbd86cf..4ca37ef6850 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -324,7 +324,6 @@ fn register_builtins(store: &mut LintStore) { store.register_renamed("exceeding_bitshifts", "arithmetic_overflow"); store.register_renamed("redundant_semicolon", "redundant_semicolons"); store.register_renamed("overlapping_patterns", "overlapping_range_endpoints"); - store.register_renamed("safe_packed_borrows", "unaligned_references"); store.register_renamed("disjoint_capture_migration", "rust_2021_incompatible_closure_captures"); store.register_renamed("or_patterns_back_compat", "rust_2021_incompatible_or_patterns"); store.register_renamed("non_fmt_panic", "non_fmt_panics"); @@ -487,6 +486,16 @@ fn register_builtins(store: &mut LintStore) { "converted into hard error, see issue #71800 \ <https://github.com/rust-lang/rust/issues/71800> for more information", ); + store.register_removed( + "safe_packed_borrows", + "converted into hard error, see issue #82523 \ + <https://github.com/rust-lang/rust/issues/82523> for more information", + ); + store.register_removed( + "unaligned_references", + "converted into hard error, see issue #82523 \ + <https://github.com/rust-lang/rust/issues/82523> for more information", + ); } fn register_internals(store: &mut LintStore) { diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index d731c10f46e..7e9ba4cd22b 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1188,51 +1188,6 @@ declare_lint! { } declare_lint! { - /// The `unaligned_references` lint detects unaligned references to fields - /// of [packed] structs. - /// - /// [packed]: https://doc.rust-lang.org/reference/type-layout.html#the-alignment-modifiers - /// - /// ### Example - /// - /// ```rust,compile_fail - /// #[repr(packed)] - /// pub struct Foo { - /// field1: u64, - /// field2: u8, - /// } - /// - /// fn main() { - /// unsafe { - /// let foo = Foo { field1: 0, field2: 0 }; - /// let _ = &foo.field1; - /// println!("{}", foo.field1); // An implicit `&` is added here, triggering the lint. - /// } - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// Creating a reference to an insufficiently aligned packed field is [undefined behavior] and - /// should be disallowed. Using an `unsafe` block does not change anything about this. Instead, - /// the code should do a copy of the data in the packed field or use raw pointers and unaligned - /// accesses. See [issue #82523] for more information. - /// - /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html - /// [issue #82523]: https://github.com/rust-lang/rust/issues/82523 - pub UNALIGNED_REFERENCES, - Deny, - "detects unaligned references to fields of packed structs", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #82523 <https://github.com/rust-lang/rust/issues/82523>", - reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow, - }; - report_in_external_macro -} - -declare_lint! { /// The `const_item_mutation` lint detects attempts to mutate a `const` /// item. /// @@ -3308,7 +3263,6 @@ declare_lint_pass! { PUB_USE_OF_PRIVATE_EXTERN_CRATE, INVALID_TYPE_PARAM_DEFAULT, RENAMED_AND_REMOVED_LINTS, - UNALIGNED_REFERENCES, CONST_ITEM_MUTATION, PATTERNS_IN_FNS_WITHOUT_BODY, MISSING_FRAGMENT_SPECIFIER, diff --git a/compiler/rustc_mir_transform/src/check_packed_ref.rs b/compiler/rustc_mir_transform/src/check_packed_ref.rs index 3e7571aa7a2..9dc8dba23a4 100644 --- a/compiler/rustc_mir_transform/src/check_packed_ref.rs +++ b/compiler/rustc_mir_transform/src/check_packed_ref.rs @@ -1,7 +1,7 @@ +use rustc_errors::struct_span_err; use rustc_middle::mir::visit::{PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::{self, TyCtxt}; -use rustc_session::lint::builtin::UNALIGNED_REFERENCES; use crate::util; use crate::MirLint; @@ -49,31 +49,22 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> { // shouldn't do. unreachable!(); } else { - let source_info = self.source_info; - let lint_root = self.body.source_scopes[source_info.scope] - .local_data - .as_ref() - .assert_crate_local() - .lint_root; - self.tcx.struct_span_lint_hir( - UNALIGNED_REFERENCES, - lint_root, - source_info.span, - "reference to packed field is unaligned", - |lint| { - lint - .note( - "fields of packed structs are not properly aligned, and creating \ - a misaligned reference is undefined behavior (even if that \ - reference is never dereferenced)", - ) - .help( - "copy the field contents to a local variable, or replace the \ - reference with a raw pointer and use `read_unaligned`/`write_unaligned` \ - (loads and stores via `*p` must be properly aligned even when using raw pointers)" - ) - }, - ); + struct_span_err!( + self.tcx.sess, + self.source_info.span, + E0793, + "reference to packed field is unaligned" + ) + .note( + "fields of packed structs are not properly aligned, and creating \ + a misaligned reference is undefined behavior (even if that \ + reference is never dereferenced)", + ).help( + "copy the field contents to a local variable, or replace the \ + reference with a raw pointer and use `read_unaligned`/`write_unaligned` \ + (loads and stores via `*p` must be properly aligned even when using raw pointers)" + ) + .emit(); } } } |
