Skip to content

Commit e825e21

Browse files
authored
Rollup merge of rust-lang#65621 - RalfJung:write_bytes, r=oli-obk
miri: add write_bytes method to Memory doing bounds-checks and supporting iterators This lets us avoid some direct `Allocation` accesses in Miri.
2 parents a160258 + f6d70b4 commit e825e21

File tree

3 files changed

+39
-20
lines changed

3 files changed

+39
-20
lines changed

src/librustc/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#![feature(nll)]
4444
#![feature(non_exhaustive)]
4545
#![feature(optin_builtin_traits)]
46+
#![feature(option_expect_none)]
4647
#![feature(range_is_empty)]
4748
#![feature(slice_patterns)]
4849
#![feature(specialization)]

src/librustc/mir/interpret/allocation.rs

+18-19
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,8 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
245245
/// as a slice.
246246
///
247247
/// It is the caller's responsibility to check bounds and alignment beforehand.
248+
/// Most likely, you want to use the `PlaceTy` and `OperandTy`-based methods
249+
/// on `InterpCx` instead.
248250
#[inline]
249251
pub fn get_bytes(
250252
&self,
@@ -275,6 +277,8 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
275277
/// so be sure to actually put data there!
276278
///
277279
/// It is the caller's responsibility to check bounds and alignment beforehand.
280+
/// Most likely, you want to use the `PlaceTy` and `OperandTy`-based methods
281+
/// on `InterpCx` instead.
278282
pub fn get_bytes_mut(
279283
&mut self,
280284
cx: &impl HasDataLayout,
@@ -297,6 +301,8 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
297301
impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
298302
/// Reads bytes until a `0` is encountered. Will error if the end of the allocation is reached
299303
/// before a `0` is found.
304+
///
305+
/// Most likely, you want to call `Memory::read_c_str` instead of this method.
300306
pub fn read_c_str(
301307
&self,
302308
cx: &impl HasDataLayout,
@@ -342,33 +348,22 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
342348
/// Writes `src` to the memory starting at `ptr.offset`.
343349
///
344350
/// It is the caller's responsibility to check bounds and alignment beforehand.
351+
/// Most likely, you want to call `Memory::write_bytes` instead of this method.
345352
pub fn write_bytes(
346353
&mut self,
347354
cx: &impl HasDataLayout,
348355
ptr: Pointer<Tag>,
349-
src: &[u8],
356+
src: impl IntoIterator<Item=u8, IntoIter: iter::ExactSizeIterator>,
350357
) -> InterpResult<'tcx>
351358
{
359+
let mut src = src.into_iter();
352360
let bytes = self.get_bytes_mut(cx, ptr, Size::from_bytes(src.len() as u64))?;
353-
bytes.clone_from_slice(src);
354-
Ok(())
355-
}
356-
357-
/// Sets `count` bytes starting at `ptr.offset` with `val`. Basically `memset`.
358-
///
359-
/// It is the caller's responsibility to check bounds and alignment beforehand.
360-
pub fn write_repeat(
361-
&mut self,
362-
cx: &impl HasDataLayout,
363-
ptr: Pointer<Tag>,
364-
val: u8,
365-
count: Size
366-
) -> InterpResult<'tcx>
367-
{
368-
let bytes = self.get_bytes_mut(cx, ptr, count)?;
369-
for b in bytes {
370-
*b = val;
361+
// `zip` would stop when the first iterator ends; we want to definitely
362+
// cover all of `bytes`.
363+
for dest in bytes {
364+
*dest = src.next().expect("iterator was shorter than it said it would be");
371365
}
366+
src.next().expect_none("iterator was longer than it said it would be");
372367
Ok(())
373368
}
374369

@@ -380,6 +375,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
380375
/// pointers being valid for ZSTs.
381376
///
382377
/// It is the caller's responsibility to check bounds and alignment beforehand.
378+
/// Most likely, you want to call `InterpCx::read_scalar` instead of this method.
383379
pub fn read_scalar(
384380
&self,
385381
cx: &impl HasDataLayout,
@@ -418,6 +414,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
418414
/// Reads a pointer-sized scalar.
419415
///
420416
/// It is the caller's responsibility to check bounds and alignment beforehand.
417+
/// Most likely, you want to call `InterpCx::read_scalar` instead of this method.
421418
pub fn read_ptr_sized(
422419
&self,
423420
cx: &impl HasDataLayout,
@@ -435,6 +432,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
435432
/// pointers being valid for ZSTs.
436433
///
437434
/// It is the caller's responsibility to check bounds and alignment beforehand.
435+
/// Most likely, you want to call `InterpCx::write_scalar` instead of this method.
438436
pub fn write_scalar(
439437
&mut self,
440438
cx: &impl HasDataLayout,
@@ -477,6 +475,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
477475
/// Writes a pointer-sized scalar.
478476
///
479477
/// It is the caller's responsibility to check bounds and alignment beforehand.
478+
/// Most likely, you want to call `InterpCx::write_scalar` instead of this method.
480479
pub fn write_ptr_sized(
481480
&mut self,
482481
cx: &impl HasDataLayout,

src/librustc_mir/interpret/memory.rs

+20-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
//! short-circuiting the empty case!
88
99
use std::collections::VecDeque;
10-
use std::ptr;
10+
use std::{ptr, iter};
1111
use std::borrow::Cow;
1212

1313
use rustc::ty::{self, Instance, ParamEnv, query::TyCtxtAt};
@@ -785,6 +785,25 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
785785
self.get(ptr.alloc_id)?.read_c_str(self, ptr)
786786
}
787787

788+
/// Writes the given stream of bytes into memory.
789+
///
790+
/// Performs appropriate bounds checks.
791+
pub fn write_bytes(
792+
&mut self,
793+
ptr: Scalar<M::PointerTag>,
794+
src: impl IntoIterator<Item=u8, IntoIter: iter::ExactSizeIterator>,
795+
) -> InterpResult<'tcx>
796+
{
797+
let src = src.into_iter();
798+
let size = Size::from_bytes(src.len() as u64);
799+
let ptr = match self.check_ptr_access(ptr, size, Align::from_bytes(1).unwrap())? {
800+
Some(ptr) => ptr,
801+
None => return Ok(()), // zero-sized access
802+
};
803+
let tcx = self.tcx.tcx;
804+
self.get_mut(ptr.alloc_id)?.write_bytes(&tcx, ptr, src)
805+
}
806+
788807
/// Expects the caller to have checked bounds and alignment.
789808
pub fn copy(
790809
&mut self,

0 commit comments

Comments
 (0)