Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

miri: add write_bytes method to Memory doing bounds-checks and supporting iterators #65621

Merged
merged 4 commits into from
Oct 22, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/librustc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#![feature(nll)]
#![feature(non_exhaustive)]
#![feature(optin_builtin_traits)]
#![feature(option_expect_none)]
#![feature(range_is_empty)]
#![feature(slice_patterns)]
#![feature(specialization)]
Expand Down
37 changes: 18 additions & 19 deletions src/librustc/mir/interpret/allocation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,8 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
/// as a slice.
///
/// It is the caller's responsibility to check bounds and alignment beforehand.
/// Most likely, you want to use the `PlaceTy` and `OperandTy`-based methods
/// on `InterpCx` instead.
#[inline]
pub fn get_bytes(
&self,
Expand Down Expand Up @@ -275,6 +277,8 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
/// so be sure to actually put data there!
///
/// It is the caller's responsibility to check bounds and alignment beforehand.
/// Most likely, you want to use the `PlaceTy` and `OperandTy`-based methods
/// on `InterpCx` instead.
pub fn get_bytes_mut(
&mut self,
cx: &impl HasDataLayout,
Expand All @@ -297,6 +301,8 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
/// Reads bytes until a `0` is encountered. Will error if the end of the allocation is reached
/// before a `0` is found.
///
/// Most likely, you want to call `Memory::read_c_str` instead of this method.
pub fn read_c_str(
&self,
cx: &impl HasDataLayout,
Expand Down Expand Up @@ -342,33 +348,22 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
/// Writes `src` to the memory starting at `ptr.offset`.
///
/// It is the caller's responsibility to check bounds and alignment beforehand.
/// Most likely, you want to call `Memory::write_bytes` instead of this method.
pub fn write_bytes(
&mut self,
cx: &impl HasDataLayout,
ptr: Pointer<Tag>,
src: &[u8],
src: impl IntoIterator<Item=u8, IntoIter: iter::ExactSizeIterator>,
) -> InterpResult<'tcx>
RalfJung marked this conversation as resolved.
Show resolved Hide resolved
{
let mut src = src.into_iter();
let bytes = self.get_bytes_mut(cx, ptr, Size::from_bytes(src.len() as u64))?;
bytes.clone_from_slice(src);
Ok(())
}

/// Sets `count` bytes starting at `ptr.offset` with `val`. Basically `memset`.
///
/// It is the caller's responsibility to check bounds and alignment beforehand.
pub fn write_repeat(
&mut self,
cx: &impl HasDataLayout,
ptr: Pointer<Tag>,
val: u8,
count: Size
) -> InterpResult<'tcx>
{
let bytes = self.get_bytes_mut(cx, ptr, count)?;
for b in bytes {
*b = val;
// `zip` would stop when the first iterator ends; we want to definitely
// cover all of `bytes`.
for dest in bytes {
*dest = src.next().expect("iterator was shorter than it said it would be");
}
src.next().expect_none("iterator was longer than it said it would be");
Ok(())
}

Expand All @@ -380,6 +375,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
/// pointers being valid for ZSTs.
///
/// It is the caller's responsibility to check bounds and alignment beforehand.
/// Most likely, you want to call `InterpCx::read_scalar` instead of this method.
pub fn read_scalar(
&self,
cx: &impl HasDataLayout,
Expand Down Expand Up @@ -418,6 +414,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
/// Reads a pointer-sized scalar.
///
/// It is the caller's responsibility to check bounds and alignment beforehand.
/// Most likely, you want to call `InterpCx::read_scalar` instead of this method.
pub fn read_ptr_sized(
&self,
cx: &impl HasDataLayout,
Expand All @@ -435,6 +432,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
/// pointers being valid for ZSTs.
///
/// It is the caller's responsibility to check bounds and alignment beforehand.
/// Most likely, you want to call `InterpCx::write_scalar` instead of this method.
pub fn write_scalar(
&mut self,
cx: &impl HasDataLayout,
Expand Down Expand Up @@ -477,6 +475,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
/// Writes a pointer-sized scalar.
///
/// It is the caller's responsibility to check bounds and alignment beforehand.
/// Most likely, you want to call `InterpCx::write_scalar` instead of this method.
pub fn write_ptr_sized(
&mut self,
cx: &impl HasDataLayout,
Expand Down
21 changes: 20 additions & 1 deletion src/librustc_mir/interpret/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
//! short-circuiting the empty case!

use std::collections::VecDeque;
use std::ptr;
use std::{ptr, iter};
use std::borrow::Cow;

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

/// Writes the given stream of bytes into memory.
///
/// Performs appropriate bounds checks.
pub fn write_bytes(
&mut self,
ptr: Scalar<M::PointerTag>,
src: impl IntoIterator<Item=u8, IntoIter: iter::ExactSizeIterator>,
) -> InterpResult<'tcx>
{
let src = src.into_iter();
let size = Size::from_bytes(src.len() as u64);
let ptr = match self.check_ptr_access(ptr, size, Align::from_bytes(1).unwrap())? {
Some(ptr) => ptr,
None => return Ok(()), // zero-sized access
};
let tcx = self.tcx.tcx;
self.get_mut(ptr.alloc_id)?.write_bytes(&tcx, ptr, src)
}

/// Expects the caller to have checked bounds and alignment.
pub fn copy(
&mut self,
Expand Down