From a8fc84561061214a35b21d30579ba18adfb14256 Mon Sep 17 00:00:00 2001 From: Nicolas Thery Date: Tue, 17 Jun 2025 14:16:00 +0200 Subject: [PATCH] Error out when `repr(align)` exceeds COFF limit The PE-COFF binary format limits section alignment to 8192 bytes. Emit error when alignment exceeds this limit to avoid crash in llvm. --- .../src/error_codes/E0806.md | 12 +++ compiler/rustc_error_codes/src/lib.rs | 1 + compiler/rustc_passes/messages.ftl | 3 + compiler/rustc_passes/src/check_attr.rs | 11 +++ compiler/rustc_passes/src/errors.rs | 7 ++ ...-align.stderr => repr-align.notwin.stderr} | 16 ++-- tests/ui/repr/repr-align.rs | 39 +++++++--- tests/ui/repr/repr-align.win.stderr | 76 +++++++++++++++++++ 8 files changed, 147 insertions(+), 18 deletions(-) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0806.md rename tests/ui/repr/{repr-align.stderr => repr-align.notwin.stderr} (81%) create mode 100644 tests/ui/repr/repr-align.win.stderr diff --git a/compiler/rustc_error_codes/src/error_codes/E0806.md b/compiler/rustc_error_codes/src/error_codes/E0806.md new file mode 100644 index 0000000000000..2339e79abbd02 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0806.md @@ -0,0 +1,12 @@ +The value of `N` that was specified for `repr(align(N))` was greater than the +PE-COFF limit (8192 bytes). + +Erroneous code example: + +```ignore (fails only on PE-COFF targets) +#[repr(align(16384))] // error: alignment must not be greater than 8192 bytes + // for COFF targets +enum Foo { + Bar(u64), +} +``` diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index f63f89748884f..3277a54ee8824 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -545,6 +545,7 @@ E0802: 0802, E0803: 0803, E0804: 0804, E0805: 0805, +E0806: 0806, ); ) } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index c668bf0733d14..0a9319a6e6179 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -481,6 +481,9 @@ passes_remove_fields = *[other] fields } +passes_repr_align_greater_than_coff_max = + alignment must not be greater than 8192 bytes for COFF targets + passes_repr_align_greater_than_target_max = alignment must not be greater than `isize::MAX` bytes .note = `isize::MAX` is {$size} for the current target diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 81259f343375e..1d4158a0a0db6 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -44,6 +44,7 @@ use rustc_session::lint::builtin::{ use rustc_session::parse::feature_err; use rustc_span::edition::Edition; use rustc_span::{BytePos, DUMMY_SP, Span, Symbol, edition, sym}; +use rustc_target::spec::BinaryFormat; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs}; use rustc_trait_selection::traits::ObligationCtxt; @@ -51,6 +52,10 @@ use tracing::debug; use crate::{errors, fluent_generated as fluent}; +// Max alignment supported for PE-COFF binary format. +// See https://learn.microsoft.com/en-us/cpp/cpp/align-cpp?view=msvc-170 +const COFF_MAX_ALIGN_BYTES: u64 = 0x2000; + #[derive(LintDiagnostic)] #[diag(passes_diagnostic_diagnostic_on_unimplemented_only_for_traits)] struct DiagnosticOnUnimplementedOnlyForTraits; @@ -1805,6 +1810,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } fn check_align(&self, align: Align, span: Span) { + if self.tcx.sess.target.binary_format == BinaryFormat::Coff { + if align.bytes() > COFF_MAX_ALIGN_BYTES { + self.dcx().emit_err(errors::InvalidReprAlignForCoff { span }); + } + } + if align.bytes() > 2_u64.pow(29) { // for values greater than 2^29, a different error will be emitted, make sure that happens self.dcx().span_delayed_bug( diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index f5023646b1917..4e3de8ce6651f 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -478,6 +478,13 @@ pub(crate) struct InvalidReprAlignForTarget { pub size: u64, } +#[derive(Diagnostic)] +#[diag(passes_repr_align_greater_than_coff_max, code = E0806)] +pub(crate) struct InvalidReprAlignForCoff { + #[primary_span] + pub span: Span, +} + #[derive(LintDiagnostic)] #[diag(passes_repr_conflicting, code = E0566)] pub(crate) struct ReprConflictingLint; diff --git a/tests/ui/repr/repr-align.stderr b/tests/ui/repr/repr-align.notwin.stderr similarity index 81% rename from tests/ui/repr/repr-align.stderr rename to tests/ui/repr/repr-align.notwin.stderr index fe919e30b1534..5f46a404337fe 100644 --- a/tests/ui/repr/repr-align.stderr +++ b/tests/ui/repr/repr-align.notwin.stderr @@ -1,47 +1,47 @@ error[E0589]: invalid `repr(align)` attribute: not an unsuffixed integer - --> $DIR/repr-align.rs:3:14 + --> $DIR/repr-align.rs:14:14 | LL | #[repr(align(16.0))] | ^^^^ error[E0589]: invalid `repr(align)` attribute: not a power of two - --> $DIR/repr-align.rs:6:14 + --> $DIR/repr-align.rs:17:14 | LL | #[repr(align(15))] | ^^ error[E0589]: invalid `repr(align)` attribute: larger than 2^29 - --> $DIR/repr-align.rs:9:14 + --> $DIR/repr-align.rs:20:14 | LL | #[repr(align(4294967296))] | ^^^^^^^^^^ error[E0589]: invalid `repr(align)` attribute: not a power of two - --> $DIR/repr-align.rs:15:14 + --> $DIR/repr-align.rs:27:14 | LL | #[repr(align(0))] | ^ error[E0589]: invalid `repr(align)` attribute: not an unsuffixed integer - --> $DIR/repr-align.rs:18:14 + --> $DIR/repr-align.rs:33:14 | LL | #[repr(align(16.0))] | ^^^^ error[E0589]: invalid `repr(align)` attribute: not a power of two - --> $DIR/repr-align.rs:21:14 + --> $DIR/repr-align.rs:36:14 | LL | #[repr(align(15))] | ^^ error[E0589]: invalid `repr(align)` attribute: larger than 2^29 - --> $DIR/repr-align.rs:24:14 + --> $DIR/repr-align.rs:39:14 | LL | #[repr(align(4294967296))] | ^^^^^^^^^^ error[E0589]: invalid `repr(align)` attribute: not a power of two - --> $DIR/repr-align.rs:30:14 + --> $DIR/repr-align.rs:46:14 | LL | #[repr(align(0))] | ^ diff --git a/tests/ui/repr/repr-align.rs b/tests/ui/repr/repr-align.rs index 6b60a765461ab..b0838d28ada53 100644 --- a/tests/ui/repr/repr-align.rs +++ b/tests/ui/repr/repr-align.rs @@ -1,33 +1,52 @@ +//@ revisions: win notwin +//@ add-minicore +//@ [win] compile-flags: --target x86_64-pc-windows-msvc +//@ [win] needs-llvm-components: x86 +//@ [notwin] compile-flags: --target x86_64-unknown-linux-gnu +//@ [notwin] needs-llvm-components: x86 + +#![feature(no_core, lang_items)] +#![no_core] #![allow(dead_code)] +extern crate minicore; +use minicore::*; -#[repr(align(16.0))] //~ ERROR: invalid `repr(align)` attribute: not an unsuffixed integer +#[repr(align(16.0))] //[notwin,win]~ ERROR: invalid `repr(align)` attribute: not an unsuffixed integer struct S0(i32); -#[repr(align(15))] //~ ERROR: invalid `repr(align)` attribute: not a power of two +#[repr(align(15))] //[notwin,win]~ ERROR: invalid `repr(align)` attribute: not a power of two struct S1(i32); -#[repr(align(4294967296))] //~ ERROR: invalid `repr(align)` attribute: larger than 2^29 +#[repr(align(4294967296))] //[notwin,win]~ ERROR: invalid `repr(align)` attribute: larger than 2^29 struct S2(i32); -#[repr(align(536870912))] // ok: this is the largest accepted alignment +#[repr(align(536870912))] //[win]~ ERROR: alignment must not be greater than 8192 bytes for COFF targets + // notwin: this is the largest accepted alignment struct S3(i32); -#[repr(align(0))] //~ ERROR: invalid `repr(align)` attribute: not a power of two +#[repr(align(0))] //[notwin,win]~ ERROR: invalid `repr(align)` attribute: not a power of two struct S4(i32); -#[repr(align(16.0))] //~ ERROR: invalid `repr(align)` attribute: not an unsuffixed integer +#[repr(align(16384))] //[win]~ ERROR: alignment must not be greater than 8192 bytes for COFF targets +struct S5(i32); + +#[repr(align(16.0))] //[notwin,win]~ ERROR: invalid `repr(align)` attribute: not an unsuffixed integer enum E0 { A, B } -#[repr(align(15))] //~ ERROR: invalid `repr(align)` attribute: not a power of two +#[repr(align(15))] //[notwin,win]~ ERROR: invalid `repr(align)` attribute: not a power of two enum E1 { A, B } -#[repr(align(4294967296))] //~ ERROR: invalid `repr(align)` attribute: larger than 2^29 +#[repr(align(4294967296))] //[notwin,win]~ ERROR: invalid `repr(align)` attribute: larger than 2^29 enum E2 { A, B } -#[repr(align(536870912))] // ok: this is the largest accepted alignment +#[repr(align(536870912))] //[win]~ ERROR: alignment must not be greater than 8192 bytes for COFF targets + // notwin: this is the largest accepted alignment enum E3 { A, B } -#[repr(align(0))] //~ ERROR: invalid `repr(align)` attribute: not a power of two +#[repr(align(0))] //[notwin,win]~ ERROR: invalid `repr(align)` attribute: not a power of two enum E4 { A, B } +#[repr(align(16384))] //[win]~ ERROR: alignment must not be greater than 8192 bytes for COFF targets +enum E5 { A, B } + fn main() {} diff --git a/tests/ui/repr/repr-align.win.stderr b/tests/ui/repr/repr-align.win.stderr new file mode 100644 index 0000000000000..8a737cf1edcb3 --- /dev/null +++ b/tests/ui/repr/repr-align.win.stderr @@ -0,0 +1,76 @@ +error[E0589]: invalid `repr(align)` attribute: not an unsuffixed integer + --> $DIR/repr-align.rs:14:14 + | +LL | #[repr(align(16.0))] + | ^^^^ + +error[E0589]: invalid `repr(align)` attribute: not a power of two + --> $DIR/repr-align.rs:17:14 + | +LL | #[repr(align(15))] + | ^^ + +error[E0589]: invalid `repr(align)` attribute: larger than 2^29 + --> $DIR/repr-align.rs:20:14 + | +LL | #[repr(align(4294967296))] + | ^^^^^^^^^^ + +error[E0589]: invalid `repr(align)` attribute: not a power of two + --> $DIR/repr-align.rs:27:14 + | +LL | #[repr(align(0))] + | ^ + +error[E0589]: invalid `repr(align)` attribute: not an unsuffixed integer + --> $DIR/repr-align.rs:33:14 + | +LL | #[repr(align(16.0))] + | ^^^^ + +error[E0589]: invalid `repr(align)` attribute: not a power of two + --> $DIR/repr-align.rs:36:14 + | +LL | #[repr(align(15))] + | ^^ + +error[E0589]: invalid `repr(align)` attribute: larger than 2^29 + --> $DIR/repr-align.rs:39:14 + | +LL | #[repr(align(4294967296))] + | ^^^^^^^^^^ + +error[E0589]: invalid `repr(align)` attribute: not a power of two + --> $DIR/repr-align.rs:46:14 + | +LL | #[repr(align(0))] + | ^ + +error[E0806]: alignment must not be greater than 8192 bytes for COFF targets + --> $DIR/repr-align.rs:23:8 + | +LL | #[repr(align(536870912))] + | ^^^^^^^^^^^^^^^^ + +error[E0806]: alignment must not be greater than 8192 bytes for COFF targets + --> $DIR/repr-align.rs:30:8 + | +LL | #[repr(align(16384))] + | ^^^^^^^^^^^^ + +error[E0806]: alignment must not be greater than 8192 bytes for COFF targets + --> $DIR/repr-align.rs:42:8 + | +LL | #[repr(align(536870912))] + | ^^^^^^^^^^^^^^^^ + +error[E0806]: alignment must not be greater than 8192 bytes for COFF targets + --> $DIR/repr-align.rs:49:8 + | +LL | #[repr(align(16384))] + | ^^^^^^^^^^^^ + +error: aborting due to 12 previous errors + +Some errors have detailed explanations: E0589, E0806. +For more information about an error, try `rustc --explain E0589`.