1
1
use rustc_apfloat:: Float ;
2
2
use rustc:: mir;
3
3
use rustc:: mir:: interpret:: { InterpResult , PointerArithmetic } ;
4
- use rustc:: ty:: layout:: { self , LayoutOf , Size } ;
4
+ use rustc:: ty:: layout:: { self , LayoutOf , Size , Align } ;
5
5
use rustc:: ty;
6
6
7
7
use crate :: {
@@ -48,56 +48,84 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
48
48
}
49
49
}
50
50
51
+ "volatile_load" => {
52
+ let place = this. deref_operand ( args[ 0 ] ) ?;
53
+ this. copy_op ( place. into ( ) , dest) ?;
54
+ }
55
+
56
+ "volatile_store" => {
57
+ let place = this. deref_operand ( args[ 0 ] ) ?;
58
+ this. copy_op ( args[ 1 ] , place. into ( ) ) ?;
59
+ }
60
+
51
61
"atomic_load" |
52
62
"atomic_load_relaxed" |
53
63
"atomic_load_acq" => {
54
- let ptr = this. deref_operand ( args[ 0 ] ) ?;
55
- let val = this. read_scalar ( ptr. into ( ) ) ?; // make sure it fits into a scalar; otherwise it cannot be atomic
56
- this. write_scalar ( val, dest) ?;
57
- }
64
+ let place = this. deref_operand ( args[ 0 ] ) ?;
65
+ let val = this. read_scalar ( place. into ( ) ) ?; // make sure it fits into a scalar; otherwise it cannot be atomic
58
66
59
- "volatile_load" => {
60
- let ptr = this. deref_operand ( args[ 0 ] ) ?;
61
- this. copy_op ( ptr. into ( ) , dest) ?;
67
+ // Check alignment requirements. Atomics must always be aligned to their size,
68
+ // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must
69
+ // be 8-aligned).
70
+ let align = Align :: from_bytes ( place. layout . size . bytes ( ) ) . unwrap ( ) ;
71
+ this. memory ( ) . check_ptr_access ( place. ptr , place. layout . size , align) ?;
72
+
73
+ this. write_scalar ( val, dest) ?;
62
74
}
63
75
64
76
"atomic_store" |
65
77
"atomic_store_relaxed" |
66
78
"atomic_store_rel" => {
67
- let ptr = this. deref_operand ( args[ 0 ] ) ?;
79
+ let place = this. deref_operand ( args[ 0 ] ) ?;
68
80
let val = this. read_scalar ( args[ 1 ] ) ?; // make sure it fits into a scalar; otherwise it cannot be atomic
69
- this. write_scalar ( val, ptr. into ( ) ) ?;
70
- }
71
81
72
- "volatile_store" => {
73
- let ptr = this. deref_operand ( args[ 0 ] ) ?;
74
- this. copy_op ( args[ 1 ] , ptr. into ( ) ) ?;
82
+ // Check alignment requirements. Atomics must always be aligned to their size,
83
+ // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must
84
+ // be 8-aligned).
85
+ let align = Align :: from_bytes ( place. layout . size . bytes ( ) ) . unwrap ( ) ;
86
+ this. memory ( ) . check_ptr_access ( place. ptr , place. layout . size , align) ?;
87
+
88
+ this. write_scalar ( val, place. into ( ) ) ?;
75
89
}
76
90
77
91
"atomic_fence_acq" => {
78
92
// we are inherently singlethreaded and singlecored, this is a nop
79
93
}
80
94
81
95
_ if intrinsic_name. starts_with ( "atomic_xchg" ) => {
82
- let ptr = this. deref_operand ( args[ 0 ] ) ?;
96
+ let place = this. deref_operand ( args[ 0 ] ) ?;
83
97
let new = this. read_scalar ( args[ 1 ] ) ?;
84
- let old = this. read_scalar ( ptr. into ( ) ) ?;
98
+ let old = this. read_scalar ( place. into ( ) ) ?;
99
+
100
+ // Check alignment requirements. Atomics must always be aligned to their size,
101
+ // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must
102
+ // be 8-aligned).
103
+ let align = Align :: from_bytes ( place. layout . size . bytes ( ) ) . unwrap ( ) ;
104
+ this. memory ( ) . check_ptr_access ( place. ptr , place. layout . size , align) ?;
105
+
85
106
this. write_scalar ( old, dest) ?; // old value is returned
86
- this. write_scalar ( new, ptr . into ( ) ) ?;
107
+ this. write_scalar ( new, place . into ( ) ) ?;
87
108
}
88
109
89
110
_ if intrinsic_name. starts_with ( "atomic_cxchg" ) => {
90
- let ptr = this. deref_operand ( args[ 0 ] ) ?;
111
+ let place = this. deref_operand ( args[ 0 ] ) ?;
91
112
let expect_old = this. read_immediate ( args[ 1 ] ) ?; // read as immediate for the sake of `binary_op()`
92
113
let new = this. read_scalar ( args[ 2 ] ) ?;
93
- let old = this. read_immediate ( ptr. into ( ) ) ?; // read as immediate for the sake of `binary_op()`
114
+ let old = this. read_immediate ( place. into ( ) ) ?; // read as immediate for the sake of `binary_op()`
115
+
116
+ // Check alignment requirements. Atomics must always be aligned to their size,
117
+ // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must
118
+ // be 8-aligned).
119
+ let align = Align :: from_bytes ( place. layout . size . bytes ( ) ) . unwrap ( ) ;
120
+ this. memory ( ) . check_ptr_access ( place. ptr , place. layout . size , align) ?;
121
+
94
122
// binary_op will bail if either of them is not a scalar
95
123
let ( eq, _) = this. binary_op ( mir:: BinOp :: Eq , old, expect_old) ?;
96
124
let res = Immediate :: ScalarPair ( old. to_scalar_or_undef ( ) , eq. into ( ) ) ;
97
125
this. write_immediate ( res, dest) ?; // old value is returned
98
126
// update ptr depending on comparison
99
127
if eq. to_bool ( ) ? {
100
- this. write_scalar ( new, ptr . into ( ) ) ?;
128
+ this. write_scalar ( new, place . into ( ) ) ?;
101
129
}
102
130
}
103
131
@@ -131,12 +159,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
131
159
"atomic_xsub_rel" |
132
160
"atomic_xsub_acqrel" |
133
161
"atomic_xsub_relaxed" => {
134
- let ptr = this. deref_operand ( args[ 0 ] ) ?;
135
- if !ptr . layout . ty . is_integral ( ) {
162
+ let place = this. deref_operand ( args[ 0 ] ) ?;
163
+ if !place . layout . ty . is_integral ( ) {
136
164
bug ! ( "Atomic arithmetic operations only work on integer types" ) ;
137
165
}
138
166
let rhs = this. read_immediate ( args[ 1 ] ) ?;
139
- let old = this. read_immediate ( ptr. into ( ) ) ?;
167
+ let old = this. read_immediate ( place. into ( ) ) ?;
168
+
169
+ // Check alignment requirements. Atomics must always be aligned to their size,
170
+ // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must
171
+ // be 8-aligned).
172
+ let align = Align :: from_bytes ( place. layout . size . bytes ( ) ) . unwrap ( ) ;
173
+ this. memory ( ) . check_ptr_access ( place. ptr , place. layout . size , align) ?;
174
+
140
175
this. write_immediate ( * old, dest) ?; // old value is returned
141
176
let ( op, neg) = match intrinsic_name. split ( '_' ) . nth ( 1 ) . unwrap ( ) {
142
177
"or" => ( mir:: BinOp :: BitOr , false ) ,
@@ -154,7 +189,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
154
189
} else {
155
190
val
156
191
} ;
157
- this. write_scalar ( val, ptr . into ( ) ) ?;
192
+ this. write_scalar ( val, place . into ( ) ) ?;
158
193
}
159
194
160
195
"breakpoint" => unimplemented ! ( ) , // halt miri
@@ -335,8 +370,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
335
370
}
336
371
337
372
"move_val_init" => {
338
- let ptr = this. deref_operand ( args[ 0 ] ) ?;
339
- this. copy_op ( args[ 1 ] , ptr . into ( ) ) ?;
373
+ let place = this. deref_operand ( args[ 0 ] ) ?;
374
+ this. copy_op ( args[ 1 ] , place . into ( ) ) ?;
340
375
}
341
376
342
377
"offset" => {
0 commit comments