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,24 @@ 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
+ // This means that `(global_state.next_base_addr + slack) % 16` is uniformly distributed.
88
+ rng. gen_range ( 0 , 16 )
89
+ } ;
90
+ // From next_base_addr + slack, round up to adjust for alignment.
91
+ let base_addr = Self :: align_addr ( global_state. next_base_addr + slack, align) ;
83
92
alloc. extra . intptrcast . base_addr . set ( Some ( base_addr) ) ;
93
+
94
+ // Remember next base address.
95
+ global_state. next_base_addr = base_addr + alloc. bytes . len ( ) as u64 ;
84
96
// Given that `next_base_addr` increases in each allocation, pushing the
85
97
// corresponding tuple keeps `int_to_ptr_map` sorted
86
98
global_state. int_to_ptr_map . push ( ( base_addr, ptr. alloc_id ) ) ;
@@ -89,13 +101,27 @@ impl<'mir, 'tcx> GlobalState {
89
101
}
90
102
} ;
91
103
92
- debug_assert_eq ! ( base_addr % alloc . align. bytes ( ) , 0 ) ; // sanity check
104
+ debug_assert_eq ! ( base_addr % align, 0 ) ; // sanity check
93
105
Ok ( base_addr + ptr. offset . bytes ( ) )
94
106
}
95
107
96
108
/// Shifts `addr` to make it aligned with `align` by rounding `addr` to the smallest multiple
97
- /// of `align` that is strictly larger to `addr`
109
+ /// of `align` that is larger or equal to `addr`
98
110
fn align_addr ( addr : u64 , align : u64 ) -> u64 {
99
- addr + align - addr % align
111
+ match addr % align {
112
+ 0 => addr,
113
+ rem => addr + align - rem
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