Skip to content

Commit

Permalink
Begin work on passing pointers to C
Browse files Browse the repository at this point in the history
  • Loading branch information
CraftSpider committed Apr 8, 2023
1 parent dd2b195 commit 18d7f36
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 3 deletions.
73 changes: 73 additions & 0 deletions src/tools/miri/src/aligned_bytes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use std::borrow::Cow;
use std::alloc::{Allocator, Global, Layout};
use std::ops::{Deref, DerefMut};
use std::ptr::NonNull;
use rustc_abi::{Size, Align};
use rustc_middle::mir::interpret::AllocBytes;

enum FillBytes<'a> {
Bytes(&'a [u8]),
Zero(Size),
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct AlignedBytes(NonNull<[u8]>, Align);

impl AlignedBytes {
fn alloc(fill: FillBytes<'_>, align: Align) -> Option<Self> {
let len = match FillBytes {
FillBytes::Bytes(b) => b.len(),
FillBytes::Zero(s) => s.bytes() as usize,
};

let layout = Layout::from_size_align(len, align.bytes() as usize)
.unwrap();
let mut bytes = Global.allocate_zeroed(layout)
.ok()?;

let slice = unsafe { bytes.as_mut() };
match fill {
FillBytes::Bytes(data) => slice.copy_from_slice(data),
FillBytes::Zero(_) => (),
}

debug_assert_eq!(bytes.as_ptr() as usize % align.bytes() as usize, 0);

Some(Self(bytes, align))
}
}

impl Deref for AlignedBytes {
type Target = [u8];

fn deref(&self) -> &Self::Target {
unsafe { self.0.as_ref() }
}
}

impl DerefMut for AlignedBytes {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { self.0.as_mut() }
}
}

impl AllocBytes for AlignedBytes {
fn adjust_to_align(self, align: Align) -> Self {
if self.align >= align {
self
} else {
let out = Self::alloc(FillBytes::Bytes(&*self), align)
.unwrap();
out
}
}

fn from_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>, align: Align) -> Self {
Self::alloc(FillBytes::Bytes(&*slice.into()), align)
.unwrap()
}

fn zeroed(size: Size, align: Align) -> Option<Self> {
Self::alloc(FillBytes::Zero(size), align)
}
}
3 changes: 3 additions & 0 deletions src/tools/miri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#![feature(local_key_cell_methods)]
#![feature(is_terminal)]
#![feature(round_ties_even)]
#![feature(allocator_api)]
// Configure clippy and other lints
#![allow(
clippy::collapsible_else_if,
Expand Down Expand Up @@ -43,6 +44,7 @@
#![recursion_limit = "256"]

extern crate rustc_apfloat;
extern crate rustc_abi;
extern crate rustc_ast;
#[macro_use]
extern crate rustc_middle;
Expand Down Expand Up @@ -73,6 +75,7 @@ mod operator;
mod range_map;
mod shims;
mod tag_gc;
mod aligned_bytes;

// Establish a "crate-wide prelude": we often import `crate::*`.

Expand Down
38 changes: 35 additions & 3 deletions src/tools/miri/src/shims/ffi_support.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
use std::ffi::c_void;
use libffi::{high::call as ffi, low::CodePtr};
use std::ops::Deref;

use rustc_middle::ty::{self as ty, IntTy, Ty, UintTy};
use rustc_span::Symbol;
use rustc_target::abi::HasDataLayout;
use rustc_hir::Mutability;
use rustc_middle::ty::layout::TyAndLayout;

use crate::*;
use crate::intptrcast::GlobalStateInner;

impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}

pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
/// Extract the scalar value from the result of reading a scalar from the machine,
/// and convert it to a `CArg`.
fn scalar_to_carg(
&mut self,
k: Scalar<Provenance>,
arg_type: Ty<'tcx>,
arg_type: TyAndLayout<'tcx>,
cx: &impl HasDataLayout,
) -> InterpResult<'tcx, CArg> {
match arg_type.kind() {
match arg_type.ty.kind() {
// If the primitive provided can be converted to a type matching the type pattern
// then create a `CArg` of this primitive value with the corresponding `CArg` constructor.
// the ints
Expand Down Expand Up @@ -56,6 +61,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// in that situation.
return Ok(CArg::USize(k.to_target_usize(cx)?.try_into().unwrap()));
}
// pointers
ty::RawPtr(ty::TypeAndMut { mutbl, ty }) if mutbl.is_not() => {
// FIXME: Add warning for types that are probably not C-portable
// FIXME: This should
// - expose the pointer
// - if it contains another pointer, mark the *inner* pointer as having wildcard provenance
if let Scalar::Ptr(ptr, _) = k {
if let Provenance::Concrete { alloc_id, tag } = ptr.provenance {
GlobalStateInner::expose_ptr(
self,
alloc_id,
tag,
)
}
let alloc = self.get_ptr_alloc(
ptr,
arg_type.layout.size(),
arg_type.layout.align().abi,
);
let qq = alloc.base_addr();
return Ok(CArg::Ptr(qq as *const c_void));
}
}
_ => {}
}
// If no primitives were returned then we have an unsupported type.
Expand Down Expand Up @@ -223,8 +251,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let mut libffi_args = Vec::<CArg>::with_capacity(args.len());
for cur_arg in args.iter() {
libffi_args.push(Self::scalar_to_carg(
ecx,
this.read_scalar(cur_arg)?,
cur_arg.layout.ty,
cur_arg.layout,
this,
)?);
}
Expand Down Expand Up @@ -268,6 +297,8 @@ pub enum CArg {
UInt64(u64),
/// usize.
USize(usize),
/// A pointer to a value
Ptr(*const c_void),
}

impl<'a> CArg {
Expand All @@ -284,6 +315,7 @@ impl<'a> CArg {
CArg::UInt32(i) => ffi::arg(i),
CArg::UInt64(i) => ffi::arg(i),
CArg::USize(i) => ffi::arg(i),
CArg::Ptr(i) => ffi::arg(i),
}
}
}

0 comments on commit 18d7f36

Please sign in to comment.