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,30 +48,44 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
48
48
}
49
49
}
50
50
51
+ "volatile_load" => {
52
+ let ptr = this. deref_operand ( args[ 0 ] ) ?;
53
+ this. copy_op ( ptr. into ( ) , dest) ?;
54
+ }
55
+
56
+ "volatile_store" => {
57
+ let ptr = this. deref_operand ( args[ 0 ] ) ?;
58
+ this. copy_op ( args[ 1 ] , ptr. into ( ) ) ?;
59
+ }
60
+
51
61
"atomic_load" |
52
62
"atomic_load_relaxed" |
53
63
"atomic_load_acq" => {
54
64
let ptr = this. deref_operand ( args[ 0 ] ) ?;
55
65
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
- }
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 ( ptr. layout . size . bytes ( ) ) . unwrap ( ) ;
71
+ this. memory ( ) . check_ptr_access ( ptr. ptr , ptr. 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
79
let ptr = 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 ( ptr. layout . size . bytes ( ) ) . unwrap ( ) ;
86
+ this. memory ( ) . check_ptr_access ( ptr. ptr , ptr. layout . size , align) ?;
87
+
88
+ this. write_scalar ( val, ptr. into ( ) ) ?;
75
89
}
76
90
77
91
"atomic_fence_acq" => {
@@ -82,6 +96,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
82
96
let ptr = this. deref_operand ( args[ 0 ] ) ?;
83
97
let new = this. read_scalar ( args[ 1 ] ) ?;
84
98
let old = this. read_scalar ( ptr. 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 ( ptr. layout . size . bytes ( ) ) . unwrap ( ) ;
104
+ this. memory ( ) . check_ptr_access ( ptr. ptr , ptr. layout . size , align) ?;
105
+
85
106
this. write_scalar ( old, dest) ?; // old value is returned
86
107
this. write_scalar ( new, ptr. into ( ) ) ?;
87
108
}
@@ -91,6 +112,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
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
114
let old = this. read_immediate ( ptr. 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 ( ptr. layout . size . bytes ( ) ) . unwrap ( ) ;
120
+ this. memory ( ) . check_ptr_access ( ptr. ptr , ptr. 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 ( ) ) ;
@@ -137,6 +165,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
137
165
}
138
166
let rhs = this. read_immediate ( args[ 1 ] ) ?;
139
167
let old = this. read_immediate ( ptr. 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 ( ptr. layout . size . bytes ( ) ) . unwrap ( ) ;
173
+ this. memory ( ) . check_ptr_access ( ptr. ptr , ptr. 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 ) ,
0 commit comments