From a10213f297be8e231f55fd6db843674a8f512140 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Thu, 6 Jul 2017 18:00:46 -0400 Subject: [PATCH 1/4] Raised alignment limit from 2^15 to 2^31 --- src/librustc/ty/layout.rs | 25 +++++++++++-------------- src/librustc/ty/mod.rs | 2 +- src/libsyntax/attr.rs | 10 +++++----- src/test/compile-fail/repr-align.rs | 2 +- src/test/run-pass/align-struct.rs | 17 +++++++++++++++++ 5 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 3212c6f07d1d6..90468d92a50ad 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -285,11 +285,11 @@ impl Size { } /// Alignment of a type in bytes, both ABI-mandated and preferred. -/// Since alignments are always powers of 2, we can pack both in one byte, -/// giving each a nibble (4 bits) for a maximum alignment of 215 = 32768. +/// Each field is a power of two. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct Align { - raw: u8 + abi: u8, + pref: u8, } impl Align { @@ -312,39 +312,36 @@ impl Align { } if bytes != 1 { Err(format!("`{}` is not a power of 2", align)) - } else if pow > 0x0f { - Err(format!("`{}` is too large", align)) } else { Ok(pow) } }; Ok(Align { - raw: pack(abi)? | (pack(pref)? << 4) + abi: pack(abi)?, + pref: pack(pref)?, }) } pub fn abi(self) -> u64 { - 1 << (self.raw & 0xf) + 1 << self.abi } pub fn pref(self) -> u64 { - 1 << (self.raw >> 4) + 1 << self.pref } pub fn min(self, other: Align) -> Align { - let abi = cmp::min(self.raw & 0x0f, other.raw & 0x0f); - let pref = cmp::min(self.raw & 0xf0, other.raw & 0xf0); Align { - raw: abi | pref + abi: cmp::min(self.abi, other.abi), + pref: cmp::min(self.pref, other.pref), } } pub fn max(self, other: Align) -> Align { - let abi = cmp::max(self.raw & 0x0f, other.raw & 0x0f); - let pref = cmp::max(self.raw & 0xf0, other.raw & 0xf0); Align { - raw: abi | pref + abi: cmp::max(self.abi, other.abi), + pref: cmp::max(self.pref, other.pref), } } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 88aef53ec9de5..0ce91b33c510d 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1398,7 +1398,7 @@ impl_stable_hash_for!(struct ReprFlags { #[derive(Copy, Clone, Eq, PartialEq, RustcEncodable, RustcDecodable, Default)] pub struct ReprOptions { pub int: Option, - pub align: u16, + pub align: u32, pub flags: ReprFlags, } diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index f0fc849c0c596..45c106f2a7f05 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -974,11 +974,11 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec let mut align_error = None; if let ast::LitKind::Int(align, ast::LitIntType::Unsuffixed) = value.node { if align.is_power_of_two() { - // rustc::ty::layout::Align restricts align to <= 32768 - if align <= 32768 { - acc.push(ReprAlign(align as u16)); + // rustc::ty::layout::Align restricts align to <= 2147483648 + if align <= 2147483648 { + acc.push(ReprAlign(align as u32)); } else { - align_error = Some("larger than 32768"); + align_error = Some("larger than 2147483648"); } } else { align_error = Some("not a power of two"); @@ -1027,7 +1027,7 @@ pub enum ReprAttr { ReprExtern, ReprPacked, ReprSimd, - ReprAlign(u16), + ReprAlign(u32), } #[derive(Eq, Hash, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)] diff --git a/src/test/compile-fail/repr-align.rs b/src/test/compile-fail/repr-align.rs index eb0b27fe9c07e..433abe943f58a 100644 --- a/src/test/compile-fail/repr-align.rs +++ b/src/test/compile-fail/repr-align.rs @@ -17,7 +17,7 @@ struct A(i32); #[repr(align(15))] //~ ERROR: invalid `repr(align)` attribute: not a power of two struct B(i32); -#[repr(align(65536))] //~ ERROR: invalid `repr(align)` attribute: larger than 32768 +#[repr(align(4294967296))] //~ ERROR: invalid `repr(align)` attribute: larger than 2147483648 struct C(i32); fn main() {} diff --git a/src/test/run-pass/align-struct.rs b/src/test/run-pass/align-struct.rs index 0b9a3594502b0..19c4c643552e1 100644 --- a/src/test/run-pass/align-struct.rs +++ b/src/test/run-pass/align-struct.rs @@ -60,6 +60,13 @@ struct AlignContainsPacked { b: Packed, } +// The align limit was originally smaller (2^15). +// Check that it works with big numbers. +#[repr(align(0x10000))] +struct AlignLarge { + stuff: [u8; 0x10000], +} + impl Align16 { // return aligned type pub fn new(i: i32) -> Align16 { @@ -193,4 +200,14 @@ pub fn main() { assert_eq!(mem::align_of_val(&a.b), 1); assert_eq!(mem::size_of_val(&a), 16); assert!(is_aligned_to(&a, 16)); + + let mut arr = [0; 0x10000]; + arr[0] = 132; + let large = AlignLarge { + stuff: arr, + }; + assert_eq!(large.stuff[0], 132); + assert_eq!(mem::align_of::(), 0x10000); + assert_eq!(mem::align_of_val(&large), 0x10000); + assert!(is_aligned_to(&large, 0x10000)); } From afed75a2d9b7e049dc26be7af3cb72297274d343 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Sat, 8 Jul 2017 10:28:20 -0400 Subject: [PATCH 2/4] Lower alignment limit down to 2^31 - 1 (from LLVM) --- src/librustc/ty/layout.rs | 10 ++++++---- src/libsyntax/attr.rs | 6 +++--- src/test/compile-fail/repr-align.rs | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 90468d92a50ad..6fb26f0dd6dbf 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -285,7 +285,9 @@ impl Size { } /// Alignment of a type in bytes, both ABI-mandated and preferred. -/// Each field is a power of two. +/// Each field is a power of two, giving the alignment a maximum +/// value of 2^(2^8 - 1), which is limited by LLVM to a i32, with +/// a maximum capacity of 2^31 - 1 or 2147483647. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct Align { abi: u8, @@ -298,7 +300,7 @@ impl Align { } pub fn from_bytes(abi: u64, pref: u64) -> Result { - let pack = |align: u64| { + let log2 = |align: u64| { // Treat an alignment of 0 bytes like 1-byte alignment. if align == 0 { return Ok(0); @@ -318,8 +320,8 @@ impl Align { }; Ok(Align { - abi: pack(abi)?, - pref: pack(pref)?, + abi: log2(abi)?, + pref: log2(pref)?, }) } diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 45c106f2a7f05..a247fe7f8a56a 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -974,11 +974,11 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec let mut align_error = None; if let ast::LitKind::Int(align, ast::LitIntType::Unsuffixed) = value.node { if align.is_power_of_two() { - // rustc::ty::layout::Align restricts align to <= 2147483648 - if align <= 2147483648 { + // rustc::ty::layout::Align restricts align to <= 2147483647 + if align <= 2147483647 { acc.push(ReprAlign(align as u32)); } else { - align_error = Some("larger than 2147483648"); + align_error = Some("larger than 2147483647"); } } else { align_error = Some("not a power of two"); diff --git a/src/test/compile-fail/repr-align.rs b/src/test/compile-fail/repr-align.rs index 433abe943f58a..bc9cf065e5a0a 100644 --- a/src/test/compile-fail/repr-align.rs +++ b/src/test/compile-fail/repr-align.rs @@ -17,7 +17,7 @@ struct A(i32); #[repr(align(15))] //~ ERROR: invalid `repr(align)` attribute: not a power of two struct B(i32); -#[repr(align(4294967296))] //~ ERROR: invalid `repr(align)` attribute: larger than 2147483648 +#[repr(align(4294967296))] //~ ERROR: invalid `repr(align)` attribute: larger than 2147483647 struct C(i32); fn main() {} From da81a33b05c216f0958e0110a1e059204d34ed85 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Sat, 8 Jul 2017 13:02:52 -0400 Subject: [PATCH 3/4] Box large array to avoid blowing the stack --- src/test/run-pass/align-struct.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/test/run-pass/align-struct.rs b/src/test/run-pass/align-struct.rs index 19c4c643552e1..59d0539916730 100644 --- a/src/test/run-pass/align-struct.rs +++ b/src/test/run-pass/align-struct.rs @@ -9,6 +9,7 @@ // except according to those terms. #![feature(attr_literals)] #![feature(repr_align)] +#![feature(box_syntax)] use std::mem; @@ -201,13 +202,14 @@ pub fn main() { assert_eq!(mem::size_of_val(&a), 16); assert!(is_aligned_to(&a, 16)); - let mut arr = [0; 0x10000]; - arr[0] = 132; - let large = AlignLarge { - stuff: arr, + let mut large = box AlignLarge { + stuff: [0; 0x10000], }; + large.stuff[0] = 132; + *large.stuff.last_mut().unwrap() = 102; assert_eq!(large.stuff[0], 132); + assert_eq!(large.stuff.last(), Some(&102)); assert_eq!(mem::align_of::(), 0x10000); - assert_eq!(mem::align_of_val(&large), 0x10000); - assert!(is_aligned_to(&large, 0x10000)); + assert_eq!(mem::align_of_val(&*large), 0x10000); + assert!(is_aligned_to(&*large, 0x10000)); } From b4973e961974ac9bdd9076acbe783b0e43242256 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Sat, 8 Jul 2017 13:43:52 -0400 Subject: [PATCH 4/4] Internally limit alignment to 2^30 --- src/librustc/ty/layout.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 6fb26f0dd6dbf..4b8b39c1f590b 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -314,6 +314,8 @@ impl Align { } if bytes != 1 { Err(format!("`{}` is not a power of 2", align)) + } else if pow > 30 { + Err(format!("`{}` is too large", align)) } else { Ok(pow) }