Skip to content

Commit 9ecde57

Browse files
committed
Move some byte and scalar accessors from Memory to Allocation
1 parent ad11856 commit 9ecde57

File tree

2 files changed

+200
-197
lines changed

2 files changed

+200
-197
lines changed

src/librustc/mir/interpret/allocation.rs

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,206 @@ impl<'tcx, Tag, Extra> Allocation<Tag, Extra> {
8686
}
8787
}
8888

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+
89289
/// Byte accessors
90290
impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
91291
/// The last argument controls whether we error out when there are undefined

0 commit comments

Comments
 (0)