1
1
use std:: cell:: { Cell , RefCell } ;
2
2
3
+ use rand:: Rng ;
4
+
3
5
use rustc:: mir:: interpret:: { AllocId , Pointer , InterpResult } ;
4
6
use rustc_mir:: interpret:: Memory ;
5
7
use rustc_target:: abi:: Size ;
@@ -73,14 +75,23 @@ impl<'mir, 'tcx> GlobalState {
73
75
let mut global_state = memory. extra . intptrcast . borrow_mut ( ) ;
74
76
75
77
let alloc = memory. get ( ptr. alloc_id ) ?;
78
+ let align = alloc. align . bytes ( ) ;
76
79
77
80
let base_addr = match alloc. extra . intptrcast . base_addr . get ( ) {
78
81
Some ( base_addr) => base_addr,
79
82
None => {
80
83
// This allocation does not have a base address yet, pick one.
81
- let base_addr = Self :: align_addr ( global_state. next_base_addr , alloc. align . bytes ( ) ) ;
82
- global_state. next_base_addr = base_addr + alloc. bytes . len ( ) as u64 ;
84
+ // Leave some space to the previous allocation, to give it some chance to be less aligned.
85
+ let slack = {
86
+ let mut rng = memory. extra . rng . as_ref ( ) . unwrap ( ) . borrow_mut ( ) ;
87
+ rng. gen_range ( 0 , align)
88
+ } ;
89
+ // From next_base_addr + slack, round up to adjust for alignment.
90
+ let base_addr = Self :: align_addr ( global_state. next_base_addr + slack, align) ;
83
91
alloc. extra . intptrcast . base_addr . set ( Some ( base_addr) ) ;
92
+
93
+ // Remember next base address.
94
+ global_state. next_base_addr = base_addr + alloc. bytes . len ( ) as u64 ;
84
95
// Given that `next_base_addr` increases in each allocation, pushing the
85
96
// corresponding tuple keeps `int_to_ptr_map` sorted
86
97
global_state. int_to_ptr_map . push ( ( base_addr, ptr. alloc_id ) ) ;
@@ -89,13 +100,28 @@ impl<'mir, 'tcx> GlobalState {
89
100
}
90
101
} ;
91
102
92
- debug_assert_eq ! ( base_addr % alloc . align. bytes ( ) , 0 ) ; // sanity check
103
+ debug_assert_eq ! ( base_addr % align, 0 ) ; // sanity check
93
104
Ok ( base_addr + ptr. offset . bytes ( ) )
94
105
}
95
106
96
107
/// Shifts `addr` to make it aligned with `align` by rounding `addr` to the smallest multiple
97
- /// of `align` that is strictly larger to `addr`
108
+ /// of `align` that is larger or equal to `addr`
98
109
fn align_addr ( addr : u64 , align : u64 ) -> u64 {
99
- addr + align - addr % align
110
+ if addr % align == 0 {
111
+ addr
112
+ } else {
113
+ addr + align - addr % align
114
+ }
115
+ }
116
+ }
117
+
118
+ #[ cfg( test) ]
119
+ mod tests {
120
+ use super :: * ;
121
+
122
+ #[ test]
123
+ fn test_align_addr ( ) {
124
+ assert_eq ! ( GlobalState :: align_addr( 37 , 4 ) , 40 ) ;
125
+ assert_eq ! ( GlobalState :: align_addr( 44 , 4 ) , 44 ) ;
100
126
}
101
127
}
0 commit comments