@@ -1491,6 +1491,9 @@ bitflags! {
1491
1491
const IS_LINEAR = 1 << 3 ;
1492
1492
// If true, don't expose any niche to type's context.
1493
1493
const HIDE_NICHE = 1 << 4 ;
1494
+ // If true, the type's layout can be randomized using
1495
+ // the seed stored in `ReprOptions.layout_seed`
1496
+ const RANDOMIZE_LAYOUT = 1 << 5 ;
1494
1497
// Any of these flags being set prevent field reordering optimisation.
1495
1498
const IS_UNOPTIMISABLE = ReprFlags :: IS_C . bits |
1496
1499
ReprFlags :: IS_SIMD . bits |
@@ -1505,6 +1508,14 @@ pub struct ReprOptions {
1505
1508
pub align : Option < Align > ,
1506
1509
pub pack : Option < Align > ,
1507
1510
pub flags : ReprFlags ,
1511
+ /// The seed to be used for randomizing a type's layout
1512
+ ///
1513
+ /// Note: This could technically be a `[u8; 16]` (a `u128`) which would
1514
+ /// be the "most accurate" hash as it'd encompass the item and crate
1515
+ /// hash without loss, but it does pay the price of being larger.
1516
+ /// Everything's a tradeoff, a `u64` seed should be sufficient for our
1517
+ /// purposes (primarily `-Z randomize-layout`)
1518
+ pub field_shuffle_seed : u64 ,
1508
1519
}
1509
1520
1510
1521
impl ReprOptions {
@@ -1513,6 +1524,11 @@ impl ReprOptions {
1513
1524
let mut size = None ;
1514
1525
let mut max_align: Option < Align > = None ;
1515
1526
let mut min_pack: Option < Align > = None ;
1527
+
1528
+ // Generate a deterministically-derived seed from the item's path hash
1529
+ // to allow for cross-crate compilation to actually work
1530
+ let field_shuffle_seed = tcx. def_path_hash ( did) . 0 . to_smaller_hash ( ) ;
1531
+
1516
1532
for attr in tcx. get_attrs ( did) . iter ( ) {
1517
1533
for r in attr:: find_repr_attrs ( & tcx. sess , attr) {
1518
1534
flags. insert ( match r {
@@ -1541,33 +1557,45 @@ impl ReprOptions {
1541
1557
}
1542
1558
}
1543
1559
1560
+ // If `-Z randomize-layout` was enabled for the type definition then we can
1561
+ // consider performing layout randomization
1562
+ if tcx. sess . opts . debugging_opts . randomize_layout {
1563
+ flags. insert ( ReprFlags :: RANDOMIZE_LAYOUT ) ;
1564
+ }
1565
+
1544
1566
// This is here instead of layout because the choice must make it into metadata.
1545
1567
if !tcx. consider_optimizing ( || format ! ( "Reorder fields of {:?}" , tcx. def_path_str( did) ) ) {
1546
1568
flags. insert ( ReprFlags :: IS_LINEAR ) ;
1547
1569
}
1548
- ReprOptions { int : size, align : max_align, pack : min_pack, flags }
1570
+
1571
+ Self { int : size, align : max_align, pack : min_pack, flags, field_shuffle_seed }
1549
1572
}
1550
1573
1551
1574
#[ inline]
1552
1575
pub fn simd ( & self ) -> bool {
1553
1576
self . flags . contains ( ReprFlags :: IS_SIMD )
1554
1577
}
1578
+
1555
1579
#[ inline]
1556
1580
pub fn c ( & self ) -> bool {
1557
1581
self . flags . contains ( ReprFlags :: IS_C )
1558
1582
}
1583
+
1559
1584
#[ inline]
1560
1585
pub fn packed ( & self ) -> bool {
1561
1586
self . pack . is_some ( )
1562
1587
}
1588
+
1563
1589
#[ inline]
1564
1590
pub fn transparent ( & self ) -> bool {
1565
1591
self . flags . contains ( ReprFlags :: IS_TRANSPARENT )
1566
1592
}
1593
+
1567
1594
#[ inline]
1568
1595
pub fn linear ( & self ) -> bool {
1569
1596
self . flags . contains ( ReprFlags :: IS_LINEAR )
1570
1597
}
1598
+
1571
1599
#[ inline]
1572
1600
pub fn hide_niche ( & self ) -> bool {
1573
1601
self . flags . contains ( ReprFlags :: HIDE_NICHE )
@@ -1594,9 +1622,17 @@ impl ReprOptions {
1594
1622
return true ;
1595
1623
}
1596
1624
}
1625
+
1597
1626
self . flags . intersects ( ReprFlags :: IS_UNOPTIMISABLE ) || self . int . is_some ( )
1598
1627
}
1599
1628
1629
+ /// Returns `true` if this type is valid for reordering and `-Z randomize-layout`
1630
+ /// was enabled for its declaration crate
1631
+ pub fn can_randomize_type_layout ( & self ) -> bool {
1632
+ !self . inhibit_struct_field_reordering_opt ( )
1633
+ && self . flags . contains ( ReprFlags :: RANDOMIZE_LAYOUT )
1634
+ }
1635
+
1600
1636
/// Returns `true` if this `#[repr()]` should inhibit union ABI optimisations.
1601
1637
pub fn inhibit_union_abi_opt ( & self ) -> bool {
1602
1638
self . c ( )
0 commit comments