@@ -86,6 +86,206 @@ impl<'tcx, Tag, Extra> Allocation<Tag, Extra> {
86
86
}
87
87
}
88
88
89
+ /// Reading and writing
90
+ impl < ' tcx , Tag : Copy , Extra : AllocationExtra < Tag > > Allocation < Tag , Extra > {
91
+ pub fn read_c_str ( & self , ptr : Pointer < M :: PointerTag > ) -> EvalResult < ' tcx , & [ u8 ] > {
92
+ let alloc = self . get ( ptr. alloc_id ) ?;
93
+ assert_eq ! ( ptr. offset. bytes( ) as usize as u64 , ptr. offset. bytes( ) ) ;
94
+ let offset = ptr. offset . bytes ( ) as usize ;
95
+ match alloc. bytes [ offset..] . iter ( ) . position ( |& c| c == 0 ) {
96
+ Some ( size) => {
97
+ let p1 = Size :: from_bytes ( ( size + 1 ) as u64 ) ;
98
+ self . check_relocations ( ptr, p1) ?;
99
+ self . check_defined ( ptr, p1) ?;
100
+ Ok ( & alloc. bytes [ offset..offset + size] )
101
+ }
102
+ None => err ! ( UnterminatedCString ( ptr. erase_tag( ) ) ) ,
103
+ }
104
+ }
105
+
106
+ pub fn check_bytes (
107
+ & self ,
108
+ ptr : Scalar < M :: PointerTag > ,
109
+ size : Size ,
110
+ allow_ptr_and_undef : bool ,
111
+ ) -> EvalResult < ' tcx > {
112
+ // Empty accesses don't need to be valid pointers, but they should still be non-NULL
113
+ let align = Align :: from_bytes ( 1 ) . unwrap ( ) ;
114
+ if size. bytes ( ) == 0 {
115
+ self . check_align ( ptr, align) ?;
116
+ return Ok ( ( ) ) ;
117
+ }
118
+ let ptr = ptr. to_ptr ( ) ?;
119
+ // Check bounds, align and relocations on the edges
120
+ self . get_bytes_with_undef_and_ptr ( ptr, size, align) ?;
121
+ // Check undef and ptr
122
+ if !allow_ptr_and_undef {
123
+ self . check_defined ( ptr, size) ?;
124
+ self . check_relocations ( ptr, size) ?;
125
+ }
126
+ Ok ( ( ) )
127
+ }
128
+
129
+ pub fn read_bytes ( & self , ptr : Scalar < M :: PointerTag > , size : Size ) -> EvalResult < ' tcx , & [ u8 ] > {
130
+ // Empty accesses don't need to be valid pointers, but they should still be non-NULL
131
+ let align = Align :: from_bytes ( 1 ) . unwrap ( ) ;
132
+ if size. bytes ( ) == 0 {
133
+ self . check_align ( ptr, align) ?;
134
+ return Ok ( & [ ] ) ;
135
+ }
136
+ self . get_bytes ( ptr. to_ptr ( ) ?, size, align)
137
+ }
138
+
139
+ pub fn write_bytes ( & mut self , ptr : Scalar < M :: PointerTag > , src : & [ u8 ] ) -> EvalResult < ' tcx > {
140
+ // Empty accesses don't need to be valid pointers, but they should still be non-NULL
141
+ let align = Align :: from_bytes ( 1 ) . unwrap ( ) ;
142
+ if src. is_empty ( ) {
143
+ self . check_align ( ptr, align) ?;
144
+ return Ok ( ( ) ) ;
145
+ }
146
+ let bytes = self . get_bytes_mut ( ptr. to_ptr ( ) ?, Size :: from_bytes ( src. len ( ) as u64 ) , align) ?;
147
+ bytes. clone_from_slice ( src) ;
148
+ Ok ( ( ) )
149
+ }
150
+
151
+ pub fn write_repeat (
152
+ & mut self ,
153
+ ptr : Scalar < M :: PointerTag > ,
154
+ val : u8 ,
155
+ count : Size
156
+ ) -> EvalResult < ' tcx > {
157
+ // Empty accesses don't need to be valid pointers, but they should still be non-NULL
158
+ let align = Align :: from_bytes ( 1 ) . unwrap ( ) ;
159
+ if count. bytes ( ) == 0 {
160
+ self . check_align ( ptr, align) ?;
161
+ return Ok ( ( ) ) ;
162
+ }
163
+ let bytes = self . get_bytes_mut ( ptr. to_ptr ( ) ?, count, align) ?;
164
+ for b in bytes {
165
+ * b = val;
166
+ }
167
+ Ok ( ( ) )
168
+ }
169
+
170
+ /// Read a *non-ZST* scalar
171
+ pub fn read_scalar (
172
+ & self ,
173
+ ptr : Pointer < M :: PointerTag > ,
174
+ ptr_align : Align ,
175
+ size : Size
176
+ ) -> EvalResult < ' tcx , ScalarMaybeUndef < M :: PointerTag > > {
177
+ // get_bytes_unchecked tests alignment and relocation edges
178
+ let bytes = self . get_bytes_with_undef_and_ptr (
179
+ ptr, size, ptr_align. min ( self . int_align ( size) )
180
+ ) ?;
181
+ // Undef check happens *after* we established that the alignment is correct.
182
+ // We must not return Ok() for unaligned pointers!
183
+ if self . check_defined ( ptr, size) . is_err ( ) {
184
+ // this inflates undefined bytes to the entire scalar, even if only a few
185
+ // bytes are undefined
186
+ return Ok ( ScalarMaybeUndef :: Undef ) ;
187
+ }
188
+ // Now we do the actual reading
189
+ let bits = read_target_uint ( self . tcx . data_layout . endian , bytes) . unwrap ( ) ;
190
+ // See if we got a pointer
191
+ if size != self . pointer_size ( ) {
192
+ // *Now* better make sure that the inside also is free of relocations.
193
+ self . check_relocations ( ptr, size) ?;
194
+ } else {
195
+ let alloc = self . get ( ptr. alloc_id ) ?;
196
+ match alloc. relocations . get ( & ptr. offset ) {
197
+ Some ( & ( tag, alloc_id) ) => {
198
+ let ptr = Pointer :: new_with_tag ( alloc_id, Size :: from_bytes ( bits as u64 ) , tag) ;
199
+ return Ok ( ScalarMaybeUndef :: Scalar ( ptr. into ( ) ) )
200
+ }
201
+ None => { } ,
202
+ }
203
+ }
204
+ // We don't. Just return the bits.
205
+ Ok ( ScalarMaybeUndef :: Scalar ( Scalar :: from_uint ( bits, size) ) )
206
+ }
207
+
208
+ pub fn read_ptr_sized (
209
+ & self ,
210
+ ptr : Pointer < M :: PointerTag > ,
211
+ ptr_align : Align
212
+ ) -> EvalResult < ' tcx , ScalarMaybeUndef < M :: PointerTag > > {
213
+ self . read_scalar ( ptr, ptr_align, self . pointer_size ( ) )
214
+ }
215
+
216
+ /// Write a *non-ZST* scalar
217
+ pub fn write_scalar (
218
+ & mut self ,
219
+ ptr : Pointer < M :: PointerTag > ,
220
+ ptr_align : Align ,
221
+ val : ScalarMaybeUndef < M :: PointerTag > ,
222
+ type_size : Size ,
223
+ ) -> EvalResult < ' tcx > {
224
+ let val = match val {
225
+ ScalarMaybeUndef :: Scalar ( scalar) => scalar,
226
+ ScalarMaybeUndef :: Undef => return self . mark_definedness ( ptr, type_size, false ) ,
227
+ } ;
228
+
229
+ let bytes = match val {
230
+ Scalar :: Ptr ( val) => {
231
+ assert_eq ! ( type_size, self . pointer_size( ) ) ;
232
+ val. offset . bytes ( ) as u128
233
+ }
234
+
235
+ Scalar :: Bits { bits, size } => {
236
+ assert_eq ! ( size as u64 , type_size. bytes( ) ) ;
237
+ debug_assert_eq ! ( truncate( bits, Size :: from_bytes( size. into( ) ) ) , bits,
238
+ "Unexpected value of size {} when writing to memory" , size) ;
239
+ bits
240
+ } ,
241
+ } ;
242
+
243
+ {
244
+ // get_bytes_mut checks alignment
245
+ let endian = self . tcx . data_layout . endian ;
246
+ let dst = self . get_bytes_mut ( ptr, type_size, ptr_align) ?;
247
+ write_target_uint ( endian, dst, bytes) . unwrap ( ) ;
248
+ }
249
+
250
+ // See if we have to also write a relocation
251
+ match val {
252
+ Scalar :: Ptr ( val) => {
253
+ self . get_mut ( ptr. alloc_id ) ?. relocations . insert (
254
+ ptr. offset ,
255
+ ( val. tag , val. alloc_id ) ,
256
+ ) ;
257
+ }
258
+ _ => { }
259
+ }
260
+
261
+ Ok ( ( ) )
262
+ }
263
+
264
+ pub fn write_ptr_sized (
265
+ & mut self ,
266
+ ptr : Pointer < M :: PointerTag > ,
267
+ ptr_align : Align ,
268
+ val : ScalarMaybeUndef < M :: PointerTag >
269
+ ) -> EvalResult < ' tcx > {
270
+ let ptr_size = self . pointer_size ( ) ;
271
+ self . write_scalar ( ptr. into ( ) , ptr_align, val, ptr_size)
272
+ }
273
+
274
+ fn int_align ( & self , size : Size ) -> Align {
275
+ // We assume pointer-sized integers have the same alignment as pointers.
276
+ // We also assume signed and unsigned integers of the same size have the same alignment.
277
+ let ity = match size. bytes ( ) {
278
+ 1 => layout:: I8 ,
279
+ 2 => layout:: I16 ,
280
+ 4 => layout:: I32 ,
281
+ 8 => layout:: I64 ,
282
+ 16 => layout:: I128 ,
283
+ _ => bug ! ( "bad integer size: {}" , size. bytes( ) ) ,
284
+ } ;
285
+ ity. align ( self ) . abi
286
+ }
287
+ }
288
+
89
289
/// Byte accessors
90
290
impl < ' tcx , Tag : Copy , Extra : AllocationExtra < Tag > > Allocation < Tag , Extra > {
91
291
/// The last argument controls whether we error out when there are undefined
0 commit comments