Auto merge of #57094 - Centril:rollup, r=Centril

Rollup of 10 pull requests

Successful merges:

 - #55470 (box: Add documentation for `From` impls)
 - #56242 (Add missing link in docs)
 - #56944 (bootstrap: Link LLVM as a dylib with ThinLTO)
 - #56978 (Add `std::os::fortanix_sgx` module)
 - #56985 (Allow testing pointers for inboundedness while forbidding dangling pointers)
 - #56986 (rustc: Move jemalloc from rustc_driver to rustc)
 - #57010 (Actually run compiletest tests on CI)
 - #57021 (Enable emission of alignment attrs for pointer params)
 - #57074 (Fix recursion limits)
 - #57085 (librustc_codegen_llvm: Don't eliminate empty structs in C ABI on linux-sparc64)

Failed merges:

r? @ghost
This commit is contained in:
bors 2018-12-24 12:31:41 +00:00
commit 50f3d6eccb
43 changed files with 515 additions and 379 deletions

View File

@ -819,7 +819,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "fortanix-sgx-abi"
version = "0.3.1"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"compiler_builtins 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2216,6 +2216,7 @@ dependencies = [
name = "rustc-main"
version = "0.0.0"
dependencies = [
"jemalloc-sys 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_codegen_ssa 0.0.0",
"rustc_driver 0.0.0",
"rustc_target 0.0.0",
@ -2402,7 +2403,6 @@ dependencies = [
"arena 0.0.0",
"env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)",
"graphviz 0.0.0",
"jemalloc-sys 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc 0.0.0",
"rustc-rayon 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2892,7 +2892,7 @@ dependencies = [
"compiler_builtins 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"core 0.0.0",
"dlmalloc 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"fortanix-sgx-abi 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"fortanix-sgx-abi 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
"panic_abort 0.0.0",
"panic_unwind 0.0.0",
@ -3449,7 +3449,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
"checksum fortanix-sgx-abi 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "26105e20b4c3f7a319db1376b54ac9a46e5761e949405553375095d05a0cee4d"
"checksum fortanix-sgx-abi 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3f8cbee5e872cf7db61a999a041f9bc4706ca7bf7df4cb914f53fabb1c1bc550"
"checksum fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213"
"checksum fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5f2a4a2034423744d2cc7ca2068453168dcdb82c438419e639a26bd87839c674"
"checksum fst 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d94485a00b1827b861dd9d1a2cc9764f9044d4c535514c0760a5a2012ef3399f"

View File

@ -48,7 +48,6 @@ impl Step for Std {
builder.info(&format!("Checking std artifacts ({} -> {})", &compiler.host, target));
run_cargo(builder,
&mut cargo,
vec![],
&libstd_stamp(builder, compiler, target),
true);
@ -95,7 +94,6 @@ impl Step for Rustc {
builder.info(&format!("Checking compiler artifacts ({} -> {})", &compiler.host, target));
run_cargo(builder,
&mut cargo,
vec![],
&librustc_stamp(builder, compiler, target),
true);
@ -146,7 +144,6 @@ impl Step for CodegenBackend {
let _folder = builder.fold_output(|| format!("stage{}-rustc_codegen_llvm", compiler.stage));
run_cargo(builder,
&mut cargo,
vec![],
&codegen_backend_stamp(builder, compiler, target, backend),
true);
}
@ -184,7 +181,6 @@ impl Step for Test {
builder.info(&format!("Checking test artifacts ({} -> {})", &compiler.host, target));
run_cargo(builder,
&mut cargo,
vec![],
&libtest_stamp(builder, compiler, target),
true);
@ -232,7 +228,6 @@ impl Step for Rustdoc {
println!("Checking rustdoc artifacts ({} -> {})", &compiler.host, target);
run_cargo(builder,
&mut cargo,
vec![],
&rustdoc_stamp(builder, compiler, target),
true);

View File

@ -29,6 +29,7 @@ use build_helper::{output, mtime, up_to_date};
use filetime::FileTime;
use serde_json;
use crate::dist;
use crate::util::{exe, libdir, is_dylib};
use crate::{Compiler, Mode, GitRepo};
use crate::native;
@ -114,7 +115,6 @@ impl Step for Std {
&compiler.host, target));
run_cargo(builder,
&mut cargo,
vec![],
&libstd_stamp(builder, compiler, target),
false);
@ -375,7 +375,6 @@ impl Step for Test {
&compiler.host, target));
run_cargo(builder,
&mut cargo,
vec![],
&libtest_stamp(builder, compiler, target),
false);
@ -503,7 +502,6 @@ impl Step for Rustc {
compiler.stage, &compiler.host, target));
run_cargo(builder,
&mut cargo,
vec![],
&librustc_stamp(builder, compiler, target),
false);
@ -646,47 +644,18 @@ impl Step for CodegenBackend {
let out_dir = builder.cargo_out(compiler, Mode::Codegen, target);
let mut cargo = builder.cargo(compiler, Mode::Codegen, target, "rustc");
let mut cargo = builder.cargo(compiler, Mode::Codegen, target, "build");
cargo.arg("--manifest-path")
.arg(builder.src.join("src/librustc_codegen_llvm/Cargo.toml"));
rustc_cargo_env(builder, &mut cargo);
let features = build_codegen_backend(&builder, &mut cargo, &compiler, target, backend);
let mut cargo_tails_args = vec![];
if builder.config.llvm_thin_lto {
cargo_tails_args.push("--".to_string());
let num_jobs = builder.jobs();
if !target.contains("msvc") {
// Here we assume that the linker is clang. If it's not, there'll
// be linker errors.
cargo_tails_args.push("-Clink-arg=-fuse-ld=lld".to_string());
cargo_tails_args.push("-Clink-arg=-flto=thin".to_string());
if builder.config.llvm_optimize {
cargo_tails_args.push("-Clink-arg=-O2".to_string());
}
// Let's make LLD respect the `-j` option.
let num_jobs_arg = format!("-Clink-arg=-Wl,--thinlto-jobs={}", num_jobs);
cargo_tails_args.push(num_jobs_arg);
} else {
// Here we assume that the linker is lld-link.exe. lld-link.exe
// does not need the extra arguments except for num_jobs
let num_jobs_arg = format!("-Clink-arg=/opt:lldltojobs={}", num_jobs);
cargo_tails_args.push(num_jobs_arg);
}
}
let tmp_stamp = out_dir.join(".tmp.stamp");
let _folder = builder.fold_output(|| format!("stage{}-rustc_codegen_llvm", compiler.stage));
let files = run_cargo(builder,
cargo.arg("--features").arg(features),
cargo_tails_args,
&tmp_stamp,
false);
if builder.config.dry_run {
@ -759,7 +728,9 @@ pub fn build_codegen_backend(builder: &Builder,
"libstdc++.a");
cargo.env("LLVM_STATIC_STDCPP", file);
}
if builder.config.llvm_link_shared {
if builder.config.llvm_link_shared ||
(builder.config.llvm_thin_lto && backend != "emscripten")
{
cargo.env("LLVM_LINK_SHARED", "1");
}
}
@ -999,6 +970,8 @@ impl Step for Assemble {
copy_lld_to_sysroot(builder, target_compiler, &lld_install);
}
dist::maybe_install_llvm_dylib(builder, target_compiler.host, &sysroot);
// Link the compiler binary itself into place
let out_dir = builder.cargo_out(build_compiler, Mode::Rustc, host);
let rustc = out_dir.join(exe("rustc_binary", &*host));
@ -1025,7 +998,6 @@ pub fn add_to_sysroot(builder: &Builder, sysroot_dst: &Path, stamp: &Path) {
pub fn run_cargo(builder: &Builder,
cargo: &mut Command,
tail_args: Vec<String>,
stamp: &Path,
is_check: bool)
-> Vec<PathBuf>
@ -1048,7 +1020,7 @@ pub fn run_cargo(builder: &Builder,
// files we need to probe for later.
let mut deps = Vec::new();
let mut toplevel = Vec::new();
let ok = stream_cargo(builder, cargo, tail_args, &mut |msg| {
let ok = stream_cargo(builder, cargo, &mut |msg| {
let filenames = match msg {
CargoMessage::CompilerArtifact { filenames, .. } => filenames,
_ => return,
@ -1173,7 +1145,6 @@ pub fn run_cargo(builder: &Builder,
pub fn stream_cargo(
builder: &Builder,
cargo: &mut Command,
tail_args: Vec<String>,
cb: &mut dyn FnMut(CargoMessage),
) -> bool {
if builder.config.dry_run {
@ -1184,10 +1155,6 @@ pub fn stream_cargo(
cargo.arg("--message-format").arg("json")
.stdout(Stdio::piped());
for arg in tail_args {
cargo.arg(arg);
}
builder.verbose(&format!("running: {:?}", cargo));
let mut child = match cargo.spawn() {
Ok(child) => child,

View File

@ -1888,13 +1888,13 @@ impl Step for HashSign {
// LLVM tools are linked dynamically.
// Note: This function does no yet support Windows but we also don't support
// linking LLVM tools dynamically on Windows yet.
fn maybe_install_llvm_dylib(builder: &Builder,
target: Interned<String>,
image: &Path) {
pub fn maybe_install_llvm_dylib(builder: &Builder,
target: Interned<String>,
sysroot: &Path) {
let src_libdir = builder
.llvm_out(target)
.join("lib");
let dst_libdir = image.join("lib/rustlib").join(&*target).join("lib");
let dst_libdir = sysroot.join("lib/rustlib").join(&*target).join("lib");
t!(fs::create_dir_all(&dst_libdir));
if target.contains("apple-darwin") {

View File

@ -87,7 +87,7 @@ impl Step for ToolBuild {
let _folder = builder.fold_output(|| format!("stage{}-{}", compiler.stage, tool));
builder.info(&format!("Building stage{} tool {} ({})", compiler.stage, tool, target));
let mut duplicates = Vec::new();
let is_expected = compile::stream_cargo(builder, &mut cargo, vec![], &mut |msg| {
let is_expected = compile::stream_cargo(builder, &mut cargo, &mut |msg| {
// Only care about big things like the RLS/Cargo for now
match tool {
| "rls"

View File

@ -21,4 +21,5 @@ RUN sh /scripts/sccache.sh
ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1
ENV SCRIPT python2.7 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu && \
python2.7 ../x.py build --stage 0 src/tools/build-manifest
python2.7 ../x.py build --stage 0 src/tools/build-manifest && \
python2.7 ../x.py test --stage 0 src/tools/compiletest

View File

@ -443,6 +443,18 @@ impl<T: ?Sized + Hasher> Hasher for Box<T> {
#[stable(feature = "from_for_ptrs", since = "1.6.0")]
impl<T> From<T> for Box<T> {
/// Converts a generic type `T` into a `Box<T>`
///
/// The conversion allocates on the heap and moves `t`
/// from the stack into it.
///
/// # Examples
/// ```rust
/// let x = 5;
/// let boxed = Box::new(5);
///
/// assert_eq!(Box::from(x), boxed);
/// ```
fn from(t: T) -> Self {
Box::new(t)
}
@ -450,6 +462,9 @@ impl<T> From<T> for Box<T> {
#[stable(feature = "pin", since = "1.33.0")]
impl<T> From<Box<T>> for Pin<Box<T>> {
/// Converts a `Box<T>` into a `Pin<Box<T>>`
///
/// This conversion does not allocate on the heap and happens in place.
fn from(boxed: Box<T>) -> Self {
// It's not possible to move or replace the insides of a `Pin<Box<T>>`
// when `T: !Unpin`, so it's safe to pin it directly without any
@ -460,6 +475,19 @@ impl<T> From<Box<T>> for Pin<Box<T>> {
#[stable(feature = "box_from_slice", since = "1.17.0")]
impl<'a, T: Copy> From<&'a [T]> for Box<[T]> {
/// Converts a `&[T]` into a `Box<[T]>`
///
/// This conversion allocates on the heap
/// and performs a copy of `slice`.
///
/// # Examples
/// ```rust
/// // create a &[u8] which will be used to create a Box<[u8]>
/// let slice: &[u8] = &[104, 101, 108, 108, 111];
/// let boxed_slice: Box<[u8]> = Box::from(slice);
///
/// println!("{:?}", boxed_slice);
/// ```
fn from(slice: &'a [T]) -> Box<[T]> {
let mut boxed = unsafe { RawVec::with_capacity(slice.len()).into_box() };
boxed.copy_from_slice(slice);
@ -469,6 +497,16 @@ impl<'a, T: Copy> From<&'a [T]> for Box<[T]> {
#[stable(feature = "box_from_slice", since = "1.17.0")]
impl<'a> From<&'a str> for Box<str> {
/// Converts a `&str` into a `Box<str>`
///
/// This conversion allocates on the heap
/// and performs a copy of `s`.
///
/// # Examples
/// ```rust
/// let boxed: Box<str> = Box::from("hello");
/// println!("{}", boxed);
/// ```
#[inline]
fn from(s: &'a str) -> Box<str> {
unsafe { from_boxed_utf8_unchecked(Box::from(s.as_bytes())) }
@ -477,6 +515,22 @@ impl<'a> From<&'a str> for Box<str> {
#[stable(feature = "boxed_str_conv", since = "1.19.0")]
impl From<Box<str>> for Box<[u8]> {
/// Converts a `Box<str>>` into a `Box<[u8]>`
///
/// This conversion does not allocate on the heap and happens in place.
///
/// # Examples
/// ```rust
/// // create a Box<str> which will be used to create a Box<[u8]>
/// let boxed: Box<str> = Box::from("hello");
/// let boxed_str: Box<[u8]> = Box::from(boxed);
///
/// // create a &[u8] which will be used to create a Box<[u8]>
/// let slice: &[u8] = &[104, 101, 108, 108, 111];
/// let boxed_slice = Box::from(slice);
///
/// assert_eq!(boxed_slice, boxed_str);
/// ```
#[inline]
fn from(s: Box<str>) -> Self {
unsafe { Box::from_raw(Box::into_raw(s) as *mut [u8]) }

View File

@ -162,7 +162,7 @@ pub trait Iterator {
/// That said, the implementation should provide a correct estimation,
/// because otherwise it would be a violation of the trait's protocol.
///
/// The default implementation returns `(0, None)` which is correct for any
/// The default implementation returns `(0, `[`None`]`)` which is correct for any
/// iterator.
///
/// [`usize`]: ../../std/primitive.usize.html

View File

@ -1271,8 +1271,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"set the MIR optimization level (0-3, default: 1)"),
mutable_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED],
"emit noalias metadata for mutable references (default: yes on LLVM >= 6)"),
arg_align_attributes: bool = (false, parse_bool, [TRACKED],
"emit align metadata for reference arguments"),
dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED],
"dump MIR state to file.
`val` is used to select which passes and functions to dump. For example:

View File

@ -456,6 +456,9 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
let linux_s390x = target.target_os == "linux"
&& target.arch == "s390x"
&& target.target_env == "gnu";
let linux_sparc64 = target.target_os == "linux"
&& target.arch == "sparc64"
&& target.target_env == "gnu";
let rust_abi = match sig.abi {
RustIntrinsic | PlatformIntrinsic | Rust | RustCall => true,
_ => false
@ -489,12 +492,6 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
attrs.pointee_size = pointee.size;
attrs.pointee_align = Some(pointee.align);
// HACK(eddyb) LLVM inserts `llvm.assume` calls when inlining functions
// with align attributes, and those calls later block optimizations.
if !is_return && !cx.tcx.sess.opts.debugging_opts.arg_align_attributes {
attrs.pointee_align = None;
}
// `Box` pointer parameters never alias because ownership is transferred
// `&mut` pointer parameters never alias other parameters,
// or mutable global data
@ -526,8 +523,9 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
if arg.layout.is_zst() {
// For some forsaken reason, x86_64-pc-windows-gnu
// doesn't ignore zero-sized struct arguments.
// The same is true for s390x-unknown-linux-gnu.
if is_return || rust_abi || (!win_x64_gnu && !linux_s390x) {
// The same is true for s390x-unknown-linux-gnu
// and sparc64-unknown-linux-gnu.
if is_return || rust_abi || (!win_x64_gnu && !linux_s390x && !linux_sparc64) {
arg.mode = PassMode::Ignore;
}
}

View File

@ -74,6 +74,10 @@ unsafe fn configure_llvm(sess: &Session) {
add("-mergefunc-use-aliases");
}
// HACK(eddyb) LLVM inserts `llvm.assume` calls to preserve align attributes
// during inlining. Unfortunately these may block other optimizations.
add("-preserve-alignment-assumptions-during-inlining=false");
for arg in &sess.opts.cg.llvm_args {
add(&(*arg));
}

View File

@ -24,6 +24,8 @@
#![allow(dead_code)]
#![feature(quote)]
#![recursion_limit="256"]
//! This crate contains codegen code that is used by all codegen backends (LLVM and others).
//! The backend-agnostic functions of this crate use functions defined in various traits that
//! have to be implemented by each backends.

View File

@ -38,8 +38,3 @@ syntax = { path = "../libsyntax" }
smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
syntax_ext = { path = "../libsyntax_ext" }
syntax_pos = { path = "../libsyntax_pos" }
[dependencies.jemalloc-sys]
version = '0.1.8'
optional = true
features = ['unprefixed_malloc_on_supported_platforms']

View File

@ -63,14 +63,6 @@ extern crate syntax;
extern crate syntax_ext;
extern crate syntax_pos;
// Note that the linkage here should be all that we need, on Linux we're not
// prefixing the symbols here so this should naturally override our default
// allocator. On OSX it should override via the zone allocator. We shouldn't
// enable this by default on other platforms, so other platforms aren't handled
// here yet.
#[cfg(feature = "jemalloc-sys")]
extern crate jemalloc_sys;
use driver::CompileController;
use pretty::{PpMode, UserIdentifiedItem};
@ -218,14 +210,7 @@ pub fn run<F>(run_compiler: F) -> isize
}
fn load_backend_from_dylib(path: &Path) -> fn() -> Box<dyn CodegenBackend> {
// Note that we're specifically using `open_global_now` here rather than
// `open`, namely we want the behavior on Unix of RTLD_GLOBAL and RTLD_NOW,
// where NOW means "bind everything right now" because we don't want
// surprises later on and RTLD_GLOBAL allows the symbols to be made
// available for future dynamic libraries opened. This is currently used by
// loading LLVM and then making its symbols available for other dynamic
// libraries.
let lib = DynamicLibrary::open_global_now(path).unwrap_or_else(|err| {
let lib = DynamicLibrary::open(Some(path)).unwrap_or_else(|err| {
let err = format!("couldn't load codegen backend {:?}: {:?}", path, err);
early_error(ErrorOutputType::default(), &err);
});

View File

@ -30,6 +30,8 @@
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![recursion_limit="256"]
#[macro_use]
extern crate syntax;
#[macro_use]

View File

@ -142,6 +142,10 @@ fn main() {
continue;
}
if flag.starts_with("-flto") {
continue;
}
// -Wdate-time is not supported by the netbsd cross compiler
if is_crossed && target.contains("netbsd") && flag.contains("date-time") {
continue;

View File

@ -262,7 +262,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
Scalar::Ptr(ptr) => {
// check this is not NULL -- which we can ensure only if this is in-bounds
// of some (potentially dead) allocation.
let align = self.check_bounds_ptr_maybe_dead(ptr)?;
let align = self.check_bounds_ptr(ptr, InboundsCheck::MaybeDead)?;
(ptr.offset.bytes(), align)
}
Scalar::Bits { bits, size } => {
@ -297,17 +297,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
/// Check if the pointer is "in-bounds". Notice that a pointer pointing at the end
/// of an allocation (i.e., at the first *inaccessible* location) *is* considered
/// in-bounds! This follows C's/LLVM's rules.
/// This function also works for deallocated allocations.
/// Use `.get(ptr.alloc_id)?.check_bounds_ptr(ptr)` if you want to force the allocation
/// to still be live.
/// If you want to check bounds before doing a memory access, better first obtain
/// an `Allocation` and call `check_bounds`.
pub fn check_bounds_ptr_maybe_dead(
pub fn check_bounds_ptr(
&self,
ptr: Pointer<M::PointerTag>,
liveness: InboundsCheck,
) -> EvalResult<'tcx, Align> {
let (allocation_size, align) = self.get_size_and_align(ptr.alloc_id);
ptr.check_in_alloc(allocation_size, InboundsCheck::MaybeDead)?;
let (allocation_size, align) = self.get_size_and_align(ptr.alloc_id, liveness)?;
ptr.check_in_alloc(allocation_size, liveness)?;
Ok(align)
}
}
@ -429,27 +427,37 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
}
}
pub fn get_size_and_align(&self, id: AllocId) -> (Size, Align) {
/// Obtain the size and alignment of an allocation, even if that allocation has been deallocated
///
/// If `liveness` is `InboundsCheck::Dead`, this function always returns `Ok`
pub fn get_size_and_align(
&self,
id: AllocId,
liveness: InboundsCheck,
) -> EvalResult<'static, (Size, Align)> {
if let Ok(alloc) = self.get(id) {
return (Size::from_bytes(alloc.bytes.len() as u64), alloc.align);
return Ok((Size::from_bytes(alloc.bytes.len() as u64), alloc.align));
}
// Could also be a fn ptr or extern static
match self.tcx.alloc_map.lock().get(id) {
Some(AllocKind::Function(..)) => (Size::ZERO, Align::from_bytes(1).unwrap()),
Some(AllocKind::Function(..)) => Ok((Size::ZERO, Align::from_bytes(1).unwrap())),
Some(AllocKind::Static(did)) => {
// The only way `get` couldn't have worked here is if this is an extern static
assert!(self.tcx.is_foreign_item(did));
// Use size and align of the type
let ty = self.tcx.type_of(did);
let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap();
(layout.size, layout.align.abi)
}
_ => {
// Must be a deallocated pointer
*self.dead_alloc_map.get(&id).expect(
"allocation missing in dead_alloc_map"
)
Ok((layout.size, layout.align.abi))
}
_ => match liveness {
InboundsCheck::MaybeDead => {
// Must be a deallocated pointer
Ok(*self.dead_alloc_map.get(&id).expect(
"allocation missing in dead_alloc_map"
))
},
InboundsCheck::Live => err!(DanglingPointerDeref),
},
}
}

View File

@ -17,7 +17,7 @@ use rustc::mir;
use rustc::ty::layout::{self, Size, LayoutOf, TyLayout, HasDataLayout, IntegerExt, VariantIdx};
use rustc::mir::interpret::{
GlobalId, AllocId,
GlobalId, AllocId, InboundsCheck,
ConstValue, Pointer, Scalar,
EvalResult, EvalErrorKind,
};
@ -647,7 +647,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
ScalarMaybeUndef::Scalar(Scalar::Ptr(ptr)) => {
// The niche must be just 0 (which an inbounds pointer value never is)
let ptr_valid = niche_start == 0 && variants_start == variants_end &&
self.memory.check_bounds_ptr_maybe_dead(ptr).is_ok();
self.memory.check_bounds_ptr(ptr, InboundsCheck::MaybeDead).is_ok();
if !ptr_valid {
return err!(InvalidDiscriminant(raw_discr.erase_tag()));
}

View File

@ -21,6 +21,8 @@
#![feature(nll)]
#![feature(rustc_diagnostic_macros)]
#![recursion_limit="256"]
#[macro_use]
extern crate rustc;
extern crate rustc_mir;

View File

@ -67,6 +67,8 @@
#![feature(nll)]
#![feature(rustc_diagnostic_macros)]
#![recursion_limit="256"]
#[macro_use] extern crate syntax;
extern crate rustc;

View File

@ -18,6 +18,8 @@
#![feature(rustc_diagnostic_macros)]
#![feature(slice_sort_by_cached_key)]
#![recursion_limit="256"]
#[macro_use]
extern crate bitflags;
#[macro_use]

View File

@ -40,7 +40,7 @@ rustc_tsan = { path = "../librustc_tsan" }
dlmalloc = { version = "0.1", features = ['rustc-dep-of-std'] }
[target.x86_64-fortanix-unknown-sgx.dependencies]
fortanix-sgx-abi = { version = "0.3.1", features = ['rustc-dep-of-std'] }
fortanix-sgx-abi = { version = "0.3.2", features = ['rustc-dep-of-std'] }
[build-dependencies]
cc = "1.0"

View File

@ -314,7 +314,7 @@
#![feature(alloc_layout_extra)]
#![feature(maybe_uninit)]
#![cfg_attr(target_env = "sgx", feature(global_asm, range_contains, slice_index_methods,
decl_macro, coerce_unsized))]
decl_macro, coerce_unsized, sgx_platform))]
#![default_lib_allocator]

View File

@ -0,0 +1,67 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Functionality specific to the `x86_64-fortanix-unknown-sgx` target.
//!
//! This includes functions to deal with memory isolation, usercalls, and the
//! SGX instruction set.
#![deny(missing_docs, missing_debug_implementations)]
#![unstable(feature = "sgx_platform", issue = "56975")]
/// Low-level interfaces to usercalls. See the [ABI documentation] for more
/// information.
///
/// [ABI documentation]: https://docs.rs/fortanix-sgx-abi/
pub mod usercalls {
pub use sys::abi::usercalls::*;
/// Primitives for allocating memory in userspace as well as copying data
/// to and from user memory.
pub mod alloc {
pub use sys::abi::usercalls::alloc;
}
/// Lowest-level interfaces to usercalls and usercall ABI type definitions.
pub mod raw {
use sys::abi::usercalls::raw::invoke_with_usercalls;
pub use sys::abi::usercalls::raw::do_usercall;
pub use sys::abi::usercalls::raw::{accept_stream, alloc, async_queues, bind_stream, close,
connect_stream, exit, flush, free, insecure_time,
launch_thread, read, read_alloc, send, wait, write};
macro_rules! define_usercallnrs {
($(fn $f:ident($($n:ident: $t:ty),*) $(-> $r:ty)*; )*) => {
/// Usercall numbers as per the ABI.
#[repr(C)]
#[unstable(feature = "sgx_platform", issue = "56975")]
#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
#[allow(missing_docs)]
pub enum UsercallNrs {
$($f,)*
}
};
}
invoke_with_usercalls!(define_usercallnrs);
// fortanix-sgx-abi re-exports
pub use sys::abi::usercalls::raw::{ByteBuffer, FifoDescriptor, Return, Usercall};
pub use sys::abi::usercalls::raw::Error;
pub use sys::abi::usercalls::raw::{EV_RETURNQ_NOT_EMPTY, EV_UNPARK, EV_USERCALLQ_NOT_FULL,
FD_STDERR, FD_STDIN, FD_STDOUT, RESULT_SUCCESS,
USERCALL_USER_DEFINED, WAIT_INDEFINITE, WAIT_NO};
pub use sys::abi::usercalls::raw::{Fd, Result, Tcs};
}
}
/// Functions for querying mapping information for pointers.
pub mod mem {
pub use sys::abi::mem::*;
}

View File

@ -29,25 +29,10 @@ cfg_if! {
#[doc(cfg(target_os = "linux"))]
pub mod linux;
} else {
// If we're not documenting libstd then we just expose everything as we
// otherwise would.
#[cfg(target_os = "android")] pub mod android;
#[cfg(target_os = "bitrig")] pub mod bitrig;
#[cfg(target_os = "dragonfly")] pub mod dragonfly;
#[cfg(target_os = "freebsd")] pub mod freebsd;
#[cfg(target_os = "haiku")] pub mod haiku;
#[cfg(target_os = "ios")] pub mod ios;
#[cfg(target_os = "macos")] pub mod macos;
#[cfg(target_os = "netbsd")] pub mod netbsd;
#[cfg(target_os = "openbsd")] pub mod openbsd;
#[cfg(target_os = "solaris")] pub mod solaris;
#[cfg(target_os = "emscripten")] pub mod emscripten;
#[cfg(target_os = "fuchsia")] pub mod fuchsia;
#[cfg(target_os = "hermit")] pub mod hermit;
// If we're not documenting libstd then we just expose the main modules
// as we otherwise would.
#[cfg(any(target_os = "redox", unix))]
#[stable(feature = "rust1", since = "1.0.0")]
@ -63,4 +48,19 @@ cfg_if! {
}
}
#[cfg(target_os = "android")] pub mod android;
#[cfg(target_os = "bitrig")] pub mod bitrig;
#[cfg(target_os = "dragonfly")] pub mod dragonfly;
#[cfg(target_os = "freebsd")] pub mod freebsd;
#[cfg(target_os = "haiku")] pub mod haiku;
#[cfg(target_os = "ios")] pub mod ios;
#[cfg(target_os = "macos")] pub mod macos;
#[cfg(target_os = "netbsd")] pub mod netbsd;
#[cfg(target_os = "openbsd")] pub mod openbsd;
#[cfg(target_os = "solaris")] pub mod solaris;
#[cfg(target_os = "emscripten")] pub mod emscripten;
#[cfg(target_os = "fuchsia")] pub mod fuchsia;
#[cfg(target_os = "hermit")] pub mod hermit;
#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] pub mod fortanix_sgx;
pub mod raw;

View File

@ -65,7 +65,7 @@ cfg_if! {
if #[cfg(any(unix, target_os = "redox"))] {
// On unix we'll document what's already available
pub use self::ext as unix_ext;
} else if #[cfg(any(target_os = "cloudabi", target_arch = "wasm32"))] {
} else if #[cfg(any(target_os = "cloudabi", target_arch = "wasm32", target_env = "sgx"))] {
// On CloudABI and wasm right now the module below doesn't compile
// (missing things in `libc` which is empty) so just omit everything
// with an empty module
@ -86,7 +86,7 @@ cfg_if! {
// On windows we'll just be documenting what's already available
#[allow(missing_docs)]
pub use self::ext as windows_ext;
} else if #[cfg(any(target_os = "cloudabi", target_arch = "wasm32"))] {
} else if #[cfg(any(target_os = "cloudabi", target_arch = "wasm32", target_env = "sgx"))] {
// On CloudABI and wasm right now the shim below doesn't compile, so
// just omit it
#[unstable(issue = "0", feature = "std_internals")]

View File

@ -10,13 +10,13 @@
// Do not remove inline: will result in relocation failure
#[inline(always)]
pub unsafe fn rel_ptr<T>(offset: u64) -> *const T {
pub(crate) unsafe fn rel_ptr<T>(offset: u64) -> *const T {
(image_base() + offset) as *const T
}
// Do not remove inline: will result in relocation failure
#[inline(always)]
pub unsafe fn rel_ptr_mut<T>(offset: u64) -> *mut T {
pub(crate) unsafe fn rel_ptr_mut<T>(offset: u64) -> *mut T {
(image_base() + offset) as *mut T
}
@ -34,6 +34,17 @@ fn image_base() -> u64 {
base
}
/// Returns `true` if the specified memory range is in the enclave.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn is_enclave_range(p: *const u8, len: usize) -> bool {
let start=p as u64;
let end=start + (len as u64);
start >= image_base() &&
end <= image_base() + (unsafe { ENCLAVE_SIZE } as u64) // unsafe ok: link-time constant
}
/// Returns `true` if the specified memory range is in userspace.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn is_user_range(p: *const u8, len: usize) -> bool {
let start=p as u64;
let end=start + (len as u64);

View File

@ -13,10 +13,10 @@ use io::Write;
// runtime features
mod reloc;
mod mem;
pub(super) mod panic;
// library features
pub mod mem;
pub mod thread;
pub mod tls;
#[macro_use]

View File

@ -10,7 +10,7 @@
#![allow(unused)]
use ptr;
use ptr::{self, NonNull};
use mem;
use cell::UnsafeCell;
use slice;
@ -39,39 +39,78 @@ use super::super::mem::is_user_range;
/// as vtable pointers) must not be leaked for confidentiality reasons.
///
/// Non-exhaustive list of specific requirements for reading from userspace:
/// * Any bit pattern is valid for this type (no `enum`s). There can be no
/// * **Any bit pattern is valid** for this type (no `enum`s). There can be no
/// guarantee that the value correctly adheres to the expectations of the
/// type, so any value must be valid for this type.
///
/// Non-exhaustive list of specific requirements for writing to userspace:
/// * No pointers to enclave memory. Memory addresses of data in enclave memory
/// must not be leaked for confidentiality reasons.
/// * No internal padding. Padding might contain previously-initialized secret
/// data stored at that memory location and must not be leaked for
/// * **No pointers to enclave memory.** Memory addresses of data in enclave
/// memory must not be leaked for confidentiality reasons.
/// * **No internal padding.** Padding might contain previously-initialized
/// secret data stored at that memory location and must not be leaked for
/// confidentiality reasons.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub unsafe trait UserSafeSized: Copy + Sized {}
#[unstable(feature = "sgx_platform", issue = "56975")]
unsafe impl UserSafeSized for u8 {}
#[unstable(feature = "sgx_platform", issue = "56975")]
unsafe impl<T> UserSafeSized for FifoDescriptor<T> {}
#[unstable(feature = "sgx_platform", issue = "56975")]
unsafe impl UserSafeSized for ByteBuffer {}
#[unstable(feature = "sgx_platform", issue = "56975")]
unsafe impl UserSafeSized for Usercall {}
#[unstable(feature = "sgx_platform", issue = "56975")]
unsafe impl UserSafeSized for Return {}
#[unstable(feature = "sgx_platform", issue = "56975")]
unsafe impl<T: UserSafeSized> UserSafeSized for [T; 2] {}
/// A type that can be represented in memory as one or more `UserSafeSized`s.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub unsafe trait UserSafe {
unsafe fn align_of() -> usize;
/// Equivalent to `mem::align_of::<Self>`.
fn align_of() -> usize;
/// Construct a pointer to `Self` given a memory range in user space.
///
/// NB. This takes a size, not a length!
unsafe fn from_raw_sized_unchecked(ptr: *const u8, size: usize) -> *const Self;
///
/// # Safety
/// The caller must ensure the memory range is in user memory, is the
/// correct size and is correctly aligned and points to the right type.
unsafe fn from_raw_sized_unchecked(ptr: *mut u8, size: usize) -> *mut Self;
/// Construct a pointer to `Self` given a memory range.
///
/// NB. This takes a size, not a length!
unsafe fn from_raw_sized(ptr: *const u8, size: usize) -> *const Self {
///
/// # Safety
/// The caller must ensure the memory range points to the correct type.
///
/// # Panics
/// This function panics if:
///
/// * The pointer is not aligned
/// * The pointer is null
/// * The pointed-to range is not in user memory
unsafe fn from_raw_sized(ptr: *mut u8, size: usize) -> NonNull<Self> {
let ret = Self::from_raw_sized_unchecked(ptr, size);
Self::check_ptr(ret);
ret
NonNull::new_unchecked(ret as _)
}
/// Check if a pointer may point to Self in user memory.
///
/// # Safety
/// The caller must ensure the memory range points to the correct type and
/// length (if this is a slice).
///
/// # Panics
/// This function panics if:
///
/// * The pointer is not aligned
/// * The pointer is null
/// * The pointed-to range is not in user memory
unsafe fn check_ptr(ptr: *const Self) {
let is_aligned = |p| -> bool {
0 == (p as usize) & (Self::align_of() - 1)
@ -83,27 +122,29 @@ pub unsafe trait UserSafe {
}
}
#[unstable(feature = "sgx_platform", issue = "56975")]
unsafe impl<T: UserSafeSized> UserSafe for T {
unsafe fn align_of() -> usize {
fn align_of() -> usize {
mem::align_of::<T>()
}
unsafe fn from_raw_sized_unchecked(ptr: *const u8, size: usize) -> *const Self {
unsafe fn from_raw_sized_unchecked(ptr: *mut u8, size: usize) -> *mut Self {
assert_eq!(size, mem::size_of::<T>());
ptr as _
}
}
#[unstable(feature = "sgx_platform", issue = "56975")]
unsafe impl<T: UserSafeSized> UserSafe for [T] {
unsafe fn align_of() -> usize {
fn align_of() -> usize {
mem::align_of::<T>()
}
unsafe fn from_raw_sized_unchecked(ptr: *const u8, size: usize) -> *const Self {
unsafe fn from_raw_sized_unchecked(ptr: *mut u8, size: usize) -> *mut Self {
let elem_size = mem::size_of::<T>();
assert_eq!(size % elem_size, 0);
let len = size / elem_size;
slice::from_raw_parts(ptr as _, len)
slice::from_raw_parts_mut(ptr as _, len)
}
}
@ -111,14 +152,40 @@ unsafe impl<T: UserSafeSized> UserSafe for [T] {
/// to `&T` in enclave memory. Access to the memory is only allowed by copying
/// to avoid TOCTTOU issues. After copying, code should make sure to completely
/// check the value before use.
///
/// It is also possible to obtain a mutable reference `&mut UserRef<T>`. Unlike
/// regular mutable references, these are not exclusive. Userspace may always
/// write to the backing memory at any time, so it can't be assumed that there
/// the pointed-to memory is uniquely borrowed. The two different refence types
/// are used solely to indicate intent: a mutable reference is for writing to
/// user memory, an immutable reference for reading from user memory.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub struct UserRef<T: ?Sized>(UnsafeCell<T>);
/// An owned type in userspace memory. `User<T>` is equivalent to `Box<T>` in
/// enclave memory. Access to the memory is only allowed by copying to avoid
/// TOCTTOU issues. The user memory will be freed when the value is dropped.
/// After copying, code should make sure to completely check the value before
/// use.
pub struct User<T: UserSafe + ?Sized>(*mut UserRef<T>);
#[unstable(feature = "sgx_platform", issue = "56975")]
pub struct User<T: UserSafe + ?Sized>(NonNull<UserRef<T>>);
trait NewUserRef<T: ?Sized> {
unsafe fn new_userref(v: T) -> Self;
}
impl<T: ?Sized> NewUserRef<*mut T> for NonNull<UserRef<T>> {
unsafe fn new_userref(v: *mut T) -> Self {
NonNull::new_unchecked(v as _)
}
}
impl<T: ?Sized> NewUserRef<NonNull<T>> for NonNull<UserRef<T>> {
unsafe fn new_userref(v: NonNull<T>) -> Self {
NonNull::new_userref(v.as_ptr())
}
}
#[unstable(feature = "sgx_platform", issue = "56975")]
impl<T: ?Sized> User<T> where T: UserSafe {
// This function returns memory that is practically uninitialized, but is
// not considered "unspecified" or "undefined" for purposes of an
@ -127,24 +194,28 @@ impl<T: ?Sized> User<T> where T: UserSafe {
fn new_uninit_bytes(size: usize) -> Self {
unsafe {
let ptr = super::alloc(size, T::align_of()).expect("User memory allocation failed");
User(T::from_raw_sized(ptr as _, size) as _)
User(NonNull::new_userref(T::from_raw_sized(ptr as _, size)))
}
}
/// Copy `val` into freshly allocated space in user memory.
pub fn new_from_enclave(val: &T) -> Self {
unsafe {
let ret = Self::new_uninit_bytes(mem::size_of_val(val));
ptr::copy(
val as *const T as *const u8,
ret.0 as *mut T as *mut u8,
ret.0.as_ptr() as *mut u8,
mem::size_of_val(val)
);
ret
}
}
/// Create an owned `User<T>` from a raw pointer. The pointer should be
/// freeable with the `free` usercall and the alignment of `T`.
/// Create an owned `User<T>` from a raw pointer.
///
/// # Safety
/// The caller must ensure `ptr` points to `T`, is freeable with the `free`
/// usercall and the alignment of `T`, and is uniquely owned.
///
/// # Panics
/// This function panics if:
@ -154,7 +225,7 @@ impl<T: ?Sized> User<T> where T: UserSafe {
/// * The pointed-to range is not in user memory
pub unsafe fn from_raw(ptr: *mut T) -> Self {
T::check_ptr(ptr);
User(ptr as _)
User(NonNull::new_userref(ptr))
}
/// Convert this value into a raw pointer. The value will no longer be
@ -162,24 +233,31 @@ impl<T: ?Sized> User<T> where T: UserSafe {
pub fn into_raw(self) -> *mut T {
let ret = self.0;
mem::forget(self);
ret as _
ret.as_ptr() as _
}
}
#[unstable(feature = "sgx_platform", issue = "56975")]
impl<T> User<T> where T: UserSafe {
/// Allocate space for `T` in user memory.
pub fn uninitialized() -> Self {
Self::new_uninit_bytes(mem::size_of::<T>())
}
}
#[unstable(feature = "sgx_platform", issue = "56975")]
impl<T> User<[T]> where [T]: UserSafe {
/// Allocate space for a `[T]` of `n` elements in user memory.
pub fn uninitialized(n: usize) -> Self {
Self::new_uninit_bytes(n * mem::size_of::<T>())
}
/// Create an owned `User<[T]>` from a raw thin pointer and a slice length.
/// The pointer should be freeable with the `free` usercall and the
/// alignment of `T`.
///
/// # Safety
/// The caller must ensure `ptr` points to `len` elements of `T`, is
/// freeable with the `free` usercall and the alignment of `T`, and is
/// uniquely owned.
///
/// # Panics
/// This function panics if:
@ -188,13 +266,17 @@ impl<T> User<[T]> where [T]: UserSafe {
/// * The pointer is null
/// * The pointed-to range is not in user memory
pub unsafe fn from_raw_parts(ptr: *mut T, len: usize) -> Self {
User(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()) as _)
User(NonNull::new_userref(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>())))
}
}
#[unstable(feature = "sgx_platform", issue = "56975")]
impl<T: ?Sized> UserRef<T> where T: UserSafe {
/// Create a `&UserRef<[T]>` from a raw pointer.
///
/// # Safety
/// The caller must ensure `ptr` points to `T`.
///
/// # Panics
/// This function panics if:
///
@ -206,7 +288,11 @@ impl<T: ?Sized> UserRef<T> where T: UserSafe {
&*(ptr as *const Self)
}
/// Create a `&mut UserRef<[T]>` from a raw pointer.
/// Create a `&mut UserRef<[T]>` from a raw pointer. See the struct
/// documentation for the nuances regarding a `&mut UserRef<T>`.
///
/// # Safety
/// The caller must ensure `ptr` points to `T`.
///
/// # Panics
/// This function panics if:
@ -219,6 +305,8 @@ impl<T: ?Sized> UserRef<T> where T: UserSafe {
&mut*(ptr as *mut Self)
}
/// Copy `val` into user memory.
///
/// # Panics
/// This function panics if the destination doesn't have the same size as
/// the source. This can happen for dynamically-sized types such as slices.
@ -233,6 +321,8 @@ impl<T: ?Sized> UserRef<T> where T: UserSafe {
}
}
/// Copy the value from user memory and place it into `dest`.
///
/// # Panics
/// This function panics if the destination doesn't have the same size as
/// the source. This can happen for dynamically-sized types such as slices.
@ -247,24 +337,32 @@ impl<T: ?Sized> UserRef<T> where T: UserSafe {
}
}
/// Obtain a raw pointer from this reference.
pub fn as_raw_ptr(&self) -> *const T {
self as *const _ as _
}
/// Obtain a raw pointer from this reference.
pub fn as_raw_mut_ptr(&mut self) -> *mut T {
self as *mut _ as _
}
}
#[unstable(feature = "sgx_platform", issue = "56975")]
impl<T> UserRef<T> where T: UserSafe {
/// Copy the value from user memory into enclave memory.
pub fn to_enclave(&self) -> T {
unsafe { ptr::read(self.0.get()) }
}
}
#[unstable(feature = "sgx_platform", issue = "56975")]
impl<T> UserRef<[T]> where [T]: UserSafe {
/// Create a `&UserRef<[T]>` from a raw thin pointer and a slice length.
///
/// # Safety
/// The caller must ensure `ptr` points to `n` elements of `T`.
///
/// # Panics
/// This function panics if:
///
@ -272,10 +370,15 @@ impl<T> UserRef<[T]> where [T]: UserSafe {
/// * The pointer is null
/// * The pointed-to range is not in user memory
pub unsafe fn from_raw_parts<'a>(ptr: *const T, len: usize) -> &'a Self {
&*(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()) as *const Self)
&*(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()).as_ptr() as *const Self)
}
/// Create a `&mut UserRef<[T]>` from a raw thin pointer and a slice length.
/// See the struct documentation for the nuances regarding a
/// `&mut UserRef<T>`.
///
/// # Safety
/// The caller must ensure `ptr` points to `n` elements of `T`.
///
/// # Panics
/// This function panics if:
@ -284,21 +387,30 @@ impl<T> UserRef<[T]> where [T]: UserSafe {
/// * The pointer is null
/// * The pointed-to range is not in user memory
pub unsafe fn from_raw_parts_mut<'a>(ptr: *mut T, len: usize) -> &'a mut Self {
&mut*(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()) as *mut Self)
&mut*(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()).as_ptr() as *mut Self)
}
/// Obtain a raw pointer to the first element of this user slice.
pub fn as_ptr(&self) -> *const T {
self.0.get() as _
}
/// Obtain a raw pointer to the first element of this user slice.
pub fn as_mut_ptr(&mut self) -> *mut T {
self.0.get() as _
}
/// Obtain the number of elements in this user slice.
pub fn len(&self) -> usize {
unsafe { (*self.0.get()).len() }
}
/// Copy the value from user memory and place it into `dest`. Afterwards,
/// `dest` will contain exactly `self.len()` elements.
///
/// # Panics
/// This function panics if the destination doesn't have the same size as
/// the source. This can happen for dynamically-sized types such as slices.
pub fn copy_to_enclave_vec(&self, dest: &mut Vec<T>) {
unsafe {
if let Some(missing) = self.len().checked_sub(dest.capacity()) {
@ -309,12 +421,14 @@ impl<T> UserRef<[T]> where [T]: UserSafe {
}
}
/// Copy the value from user memory into a vector in enclave memory.
pub fn to_enclave(&self) -> Vec<T> {
let mut ret = Vec::with_capacity(self.len());
self.copy_to_enclave_vec(&mut ret);
ret
}
/// Returns an iterator over the slice.
pub fn iter(&self) -> Iter<T>
where T: UserSafe // FIXME: should be implied by [T]: UserSafe?
{
@ -323,6 +437,7 @@ impl<T> UserRef<[T]> where [T]: UserSafe {
}
}
/// Returns an iterator that allows modifying each value.
pub fn iter_mut(&mut self) -> IterMut<T>
where T: UserSafe // FIXME: should be implied by [T]: UserSafe?
{
@ -332,8 +447,13 @@ impl<T> UserRef<[T]> where [T]: UserSafe {
}
}
/// Immutable user slice iterator
///
/// This struct is created by the `iter` method on `UserRef<[T]>`.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub struct Iter<'a, T: 'a + UserSafe>(slice::Iter<'a, T>);
#[unstable(feature = "sgx_platform", issue = "56975")]
impl<'a, T: UserSafe> Iterator for Iter<'a, T> {
type Item = &'a UserRef<T>;
@ -345,8 +465,13 @@ impl<'a, T: UserSafe> Iterator for Iter<'a, T> {
}
}
/// Mutable user slice iterator
///
/// This struct is created by the `iter_mut` method on `UserRef<[T]>`.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub struct IterMut<'a, T: 'a + UserSafe>(slice::IterMut<'a, T>);
#[unstable(feature = "sgx_platform", issue = "56975")]
impl<'a, T: UserSafe> Iterator for IterMut<'a, T> {
type Item = &'a mut UserRef<T>;
@ -358,31 +483,36 @@ impl<'a, T: UserSafe> Iterator for IterMut<'a, T> {
}
}
#[unstable(feature = "sgx_platform", issue = "56975")]
impl<T: ?Sized> Deref for User<T> where T: UserSafe {
type Target = UserRef<T>;
fn deref(&self) -> &Self::Target {
unsafe { &*self.0 }
unsafe { &*self.0.as_ptr() }
}
}
#[unstable(feature = "sgx_platform", issue = "56975")]
impl<T: ?Sized> DerefMut for User<T> where T: UserSafe {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut*self.0 }
unsafe { &mut*self.0.as_ptr() }
}
}
#[unstable(feature = "sgx_platform", issue = "56975")]
impl<T: ?Sized> Drop for User<T> where T: UserSafe {
fn drop(&mut self) {
unsafe {
let ptr = (*self.0).0.get();
let ptr = (*self.0.as_ptr()).0.get();
super::free(ptr as _, mem::size_of_val(&mut*ptr), T::align_of());
}
}
}
#[unstable(feature = "sgx_platform", issue = "56975")]
impl<T: CoerceUnsized<U>, U> CoerceUnsized<UserRef<U>> for UserRef<T> {}
#[unstable(feature = "sgx_platform", issue = "56975")]
impl<T, I: SliceIndex<[T]>> Index<I> for UserRef<[T]> where [T]: UserSafe, I::Output: UserSafe {
type Output = UserRef<I::Output>;
@ -394,6 +524,7 @@ impl<T, I: SliceIndex<[T]>> Index<I> for UserRef<[T]> where [T]: UserSafe, I::Ou
}
}
#[unstable(feature = "sgx_platform", issue = "56975")]
impl<T, I: SliceIndex<[T]>> IndexMut<I> for UserRef<[T]> where [T]: UserSafe, I::Output: UserSafe {
#[inline]
fn index_mut(&mut self, index: I) -> &mut UserRef<I::Output> {
@ -402,3 +533,21 @@ impl<T, I: SliceIndex<[T]>> IndexMut<I> for UserRef<[T]> where [T]: UserSafe, I:
}
}
}
#[unstable(feature = "sgx_platform", issue = "56975")]
impl UserRef<super::raw::ByteBuffer> {
/// Copy the user memory range pointed to by the user `ByteBuffer` to
/// enclave memory.
///
/// # Panics
/// This function panics if:
///
/// * The pointer in the user `ByteBuffer` is null
/// * The pointed-to range in the user `ByteBuffer` is not in user memory
pub fn copy_user_buffer(&self) -> Vec<u8> {
unsafe {
let buf = self.to_enclave();
User::from_raw_parts(buf.data as _, buf.len).to_enclave()
}
}
}

View File

@ -8,22 +8,17 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
pub use fortanix_sgx_abi::*;
use io::{Error as IoError, Result as IoResult};
use time::Duration;
pub mod alloc;
pub(crate) mod alloc;
#[macro_use]
mod raw;
pub(crate) mod raw;
pub(crate) fn copy_user_buffer(buf: &alloc::UserRef<ByteBuffer>) -> Vec<u8> {
unsafe {
let buf = buf.to_enclave();
alloc::User::from_raw_parts(buf.data as _, buf.len).to_enclave()
}
}
use self::raw::*;
/// Usercall `read`. See the ABI documentation for more information.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn read(fd: Fd, buf: &mut [u8]) -> IoResult<usize> {
unsafe {
let mut userbuf = alloc::User::<[u8]>::uninitialized(buf.len());
@ -33,6 +28,18 @@ pub fn read(fd: Fd, buf: &mut [u8]) -> IoResult<usize> {
}
}
/// Usercall `read_alloc`. See the ABI documentation for more information.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn read_alloc(fd: Fd) -> IoResult<Vec<u8>> {
unsafe {
let mut userbuf = alloc::User::<ByteBuffer>::uninitialized();
raw::read_alloc(fd, userbuf.as_raw_mut_ptr()).from_sgx_result()?;
Ok(userbuf.copy_user_buffer())
}
}
/// Usercall `write`. See the ABI documentation for more information.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn write(fd: Fd, buf: &[u8]) -> IoResult<usize> {
unsafe {
let userbuf = alloc::User::new_from_enclave(buf);
@ -40,19 +47,25 @@ pub fn write(fd: Fd, buf: &[u8]) -> IoResult<usize> {
}
}
/// Usercall `flush`. See the ABI documentation for more information.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn flush(fd: Fd) -> IoResult<()> {
unsafe { raw::flush(fd).from_sgx_result() }
}
/// Usercall `close`. See the ABI documentation for more information.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn close(fd: Fd) {
unsafe { raw::close(fd) }
}
fn string_from_bytebuffer(buf: &alloc::UserRef<ByteBuffer>, usercall: &str, arg: &str) -> String {
String::from_utf8(copy_user_buffer(buf))
String::from_utf8(buf.copy_user_buffer())
.unwrap_or_else(|_| panic!("Usercall {}: expected {} to be valid UTF-8", usercall, arg))
}
/// Usercall `bind_stream`. See the ABI documentation for more information.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn bind_stream(addr: &str) -> IoResult<(Fd, String)> {
unsafe {
let addr_user = alloc::User::new_from_enclave(addr.as_bytes());
@ -67,6 +80,8 @@ pub fn bind_stream(addr: &str) -> IoResult<(Fd, String)> {
}
}
/// Usercall `accept_stream`. See the ABI documentation for more information.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn accept_stream(fd: Fd) -> IoResult<(Fd, String, String)> {
unsafe {
let mut bufs = alloc::User::<[ByteBuffer; 2]>::uninitialized();
@ -84,6 +99,8 @@ pub fn accept_stream(fd: Fd) -> IoResult<(Fd, String, String)> {
}
}
/// Usercall `connect_stream`. See the ABI documentation for more information.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn connect_stream(addr: &str) -> IoResult<(Fd, String, String)> {
unsafe {
let addr_user = alloc::User::new_from_enclave(addr.as_bytes());
@ -103,31 +120,45 @@ pub fn connect_stream(addr: &str) -> IoResult<(Fd, String, String)> {
}
}
pub fn launch_thread() -> IoResult<()> {
unsafe { raw::launch_thread().from_sgx_result() }
/// Usercall `launch_thread`. See the ABI documentation for more information.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub unsafe fn launch_thread() -> IoResult<()> {
raw::launch_thread().from_sgx_result()
}
/// Usercall `exit`. See the ABI documentation for more information.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn exit(panic: bool) -> ! {
unsafe { raw::exit(panic) }
}
/// Usercall `wait`. See the ABI documentation for more information.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn wait(event_mask: u64, timeout: u64) -> IoResult<u64> {
unsafe { raw::wait(event_mask, timeout).from_sgx_result() }
}
/// Usercall `send`. See the ABI documentation for more information.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn send(event_set: u64, tcs: Option<Tcs>) -> IoResult<()> {
unsafe { raw::send(event_set, tcs).from_sgx_result() }
}
/// Usercall `insecure_time`. See the ABI documentation for more information.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn insecure_time() -> Duration {
let t = unsafe { raw::insecure_time() };
Duration::new(t / 1_000_000_000, (t % 1_000_000_000) as _)
}
/// Usercall `alloc`. See the ABI documentation for more information.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn alloc(size: usize, alignment: usize) -> IoResult<*mut u8> {
unsafe { raw::alloc(size, alignment).from_sgx_result() }
}
#[unstable(feature = "sgx_platform", issue = "56975")]
#[doc(inline)]
pub use self::raw::free;
fn check_os_error(err: Result) -> i32 {

View File

@ -10,7 +10,8 @@
#![allow(unused)]
use fortanix_sgx_abi::*;
#[unstable(feature = "sgx_platform", issue = "56975")]
pub use fortanix_sgx_abi::*;
use ptr::NonNull;
@ -21,7 +22,16 @@ extern "C" {
fn usercall(nr: u64, p1: u64, p2: u64, _ignore: u64, p3: u64, p4: u64) -> UsercallReturn;
}
unsafe fn do_usercall(nr: u64, p1: u64, p2: u64, p3: u64, p4: u64) -> (u64, u64) {
/// Perform the raw usercall operation as defined in the ABI calling convention.
///
/// # Safety
/// The caller must ensure to pass parameters appropriate for the usercall `nr`
/// and to observe all requirements specified in the ABI.
///
/// # Panics
/// Panics if `nr` is 0.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub unsafe fn do_usercall(nr: u64, p1: u64, p2: u64, p3: u64, p4: u64) -> (u64, u64) {
if nr==0 { panic!("Invalid usercall number {}",nr) }
let UsercallReturn(a, b) = usercall(nr,p1,p2,0,p3,p4);
(a, b)
@ -169,6 +179,9 @@ impl<T: RegisterArgument, U: RegisterArgument> ReturnValue for (T, U) {
macro_rules! enclave_usercalls_internal_define_usercalls {
(def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty,
$n3:ident: $t3:ty, $n4:ident: $t4:ty) -> $r:ty) => (
/// This is the raw function definition, see the ABI documentation for
/// more information.
#[unstable(feature = "sgx_platform", issue = "56975")]
#[inline(always)]
pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3, $n4: $t4) -> $r {
ReturnValue::from_registers(stringify!($f), do_usercall(
@ -181,6 +194,9 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
}
);
(def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty, $n3:ident: $t3:ty) -> $r:ty) => (
/// This is the raw function definition, see the ABI documentation for
/// more information.
#[unstable(feature = "sgx_platform", issue = "56975")]
#[inline(always)]
pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3) -> $r {
ReturnValue::from_registers(stringify!($f), do_usercall(
@ -193,6 +209,9 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
}
);
(def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty) -> $r:ty) => (
/// This is the raw function definition, see the ABI documentation for
/// more information.
#[unstable(feature = "sgx_platform", issue = "56975")]
#[inline(always)]
pub unsafe fn $f($n1: $t1, $n2: $t2) -> $r {
ReturnValue::from_registers(stringify!($f), do_usercall(
@ -204,6 +223,9 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
}
);
(def fn $f:ident($n1:ident: $t1:ty) -> $r:ty) => (
/// This is the raw function definition, see the ABI documentation for
/// more information.
#[unstable(feature = "sgx_platform", issue = "56975")]
#[inline(always)]
pub unsafe fn $f($n1: $t1) -> $r {
ReturnValue::from_registers(stringify!($f), do_usercall(
@ -214,6 +236,9 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
}
);
(def fn $f:ident() -> $r:ty) => (
/// This is the raw function definition, see the ABI documentation for
/// more information.
#[unstable(feature = "sgx_platform", issue = "56975")]
#[inline(always)]
pub unsafe fn $f() -> $r {
ReturnValue::from_registers(stringify!($f), do_usercall(

View File

@ -9,7 +9,7 @@
// except according to those terms.
use ffi::OsString;
use super::abi::usercalls::{copy_user_buffer, alloc, ByteBuffer};
use super::abi::usercalls::{alloc, raw::ByteBuffer};
use sync::atomic::{AtomicUsize, Ordering};
use sys::os_str::Buf;
use sys_common::FromInner;
@ -22,7 +22,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) {
if argc != 0 {
let args = alloc::User::<[ByteBuffer]>::from_raw_parts(argv as _, argc as _);
let args = args.iter()
.map( |a| OsString::from_inner(Buf { inner: copy_user_buffer(a) }) )
.map( |a| OsString::from_inner(Buf { inner: a.copy_user_buffer() }) )
.collect::<ArgsStore>();
ARGS.store(Box::into_raw(Box::new(args)) as _, Ordering::Relaxed);
}

View File

@ -29,7 +29,7 @@ struct Socket {
}
impl Socket {
fn new(fd: usercalls::Fd, local_addr: String) -> Socket {
fn new(fd: usercalls::raw::Fd, local_addr: String) -> Socket {
Socket { inner: Arc::new(FileDesc::new(fd)), local_addr }
}
}

View File

@ -75,7 +75,7 @@ impl Thread {
pub fn yield_now() {
assert_eq!(
usercalls::wait(0, usercalls::WAIT_NO).unwrap_err().kind(),
usercalls::wait(0, usercalls::raw::WAIT_NO).unwrap_err().kind(),
io::ErrorKind::WouldBlock
);
}

View File

@ -24,6 +24,8 @@
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![recursion_limit="256"]
extern crate fmt_macros;
#[macro_use]
extern crate syntax;

View File

@ -15,5 +15,10 @@ rustc_driver = { path = "../librustc_driver" }
# crate is intended to be used by codegen backends, which may not be in-tree.
rustc_codegen_ssa = { path = "../librustc_codegen_ssa" }
[dependencies.jemalloc-sys]
version = '0.1.8'
optional = true
features = ['unprefixed_malloc_on_supported_platforms']
[features]
jemalloc = ['rustc_driver/jemalloc-sys']
jemalloc = ['jemalloc-sys']

View File

@ -23,6 +23,14 @@ extern {}
extern crate rustc_driver;
// Note that the linkage here should be all that we need, on Linux we're not
// prefixing the symbols here so this should naturally override our default
// allocator. On OSX it should override via the zone allocator. We shouldn't
// enable this by default on other platforms, so other platforms aren't handled
// here yet.
#[cfg(feature = "jemalloc-sys")]
extern crate jemalloc_sys;
fn main() {
rustc_driver::set_sigpipe_handler();
rustc_driver::main()

View File

@ -28,37 +28,37 @@ pub fn boolean(x: bool) -> bool {
x
}
// CHECK: @readonly_borrow(i32* noalias readonly dereferenceable(4) %arg0)
// CHECK: @readonly_borrow(i32* noalias readonly align 4 dereferenceable(4) %arg0)
// FIXME #25759 This should also have `nocapture`
#[no_mangle]
pub fn readonly_borrow(_: &i32) {
}
// CHECK: @static_borrow(i32* noalias readonly dereferenceable(4) %arg0)
// CHECK: @static_borrow(i32* noalias readonly align 4 dereferenceable(4) %arg0)
// static borrow may be captured
#[no_mangle]
pub fn static_borrow(_: &'static i32) {
}
// CHECK: @named_borrow(i32* noalias readonly dereferenceable(4) %arg0)
// CHECK: @named_borrow(i32* noalias readonly align 4 dereferenceable(4) %arg0)
// borrow with named lifetime may be captured
#[no_mangle]
pub fn named_borrow<'r>(_: &'r i32) {
}
// CHECK: @unsafe_borrow(i16* dereferenceable(2) %arg0)
// CHECK: @unsafe_borrow(i16* align 2 dereferenceable(2) %arg0)
// unsafe interior means this isn't actually readonly and there may be aliases ...
#[no_mangle]
pub fn unsafe_borrow(_: &UnsafeInner) {
}
// CHECK: @mutable_unsafe_borrow(i16* dereferenceable(2) %arg0)
// CHECK: @mutable_unsafe_borrow(i16* align 2 dereferenceable(2) %arg0)
// ... unless this is a mutable borrow, those never alias
#[no_mangle]
pub fn mutable_unsafe_borrow(_: &mut UnsafeInner) {
}
// CHECK: @mutable_borrow(i32* dereferenceable(4) %arg0)
// CHECK: @mutable_borrow(i32* align 4 dereferenceable(4) %arg0)
// FIXME #25759 This should also have `nocapture`
#[no_mangle]
pub fn mutable_borrow(_: &mut i32) {
@ -69,13 +69,13 @@ pub fn mutable_borrow(_: &mut i32) {
pub fn indirect_struct(_: S) {
}
// CHECK: @borrowed_struct(%S* noalias readonly dereferenceable(32) %arg0)
// CHECK: @borrowed_struct(%S* noalias readonly align 4 dereferenceable(32) %arg0)
// FIXME #25759 This should also have `nocapture`
#[no_mangle]
pub fn borrowed_struct(_: &S) {
}
// CHECK: noalias align 4 dereferenceable(4) i32* @_box(i32* noalias dereferenceable(4) %x)
// CHECK: noalias align 4 dereferenceable(4) i32* @_box(i32* noalias align 4 dereferenceable(4) %x)
#[no_mangle]
pub fn _box(x: Box<i32>) -> Box<i32> {
x
@ -95,48 +95,48 @@ pub fn struct_return() -> S {
pub fn helper(_: usize) {
}
// CHECK: @slice([0 x i8]* noalias nonnull readonly %arg0.0, [[USIZE]] %arg0.1)
// CHECK: @slice([0 x i8]* noalias nonnull readonly align 1 %arg0.0, [[USIZE]] %arg0.1)
// FIXME #25759 This should also have `nocapture`
#[no_mangle]
pub fn slice(_: &[u8]) {
}
// CHECK: @mutable_slice([0 x i8]* nonnull %arg0.0, [[USIZE]] %arg0.1)
// CHECK: @mutable_slice([0 x i8]* nonnull align 1 %arg0.0, [[USIZE]] %arg0.1)
// FIXME #25759 This should also have `nocapture`
#[no_mangle]
pub fn mutable_slice(_: &mut [u8]) {
}
// CHECK: @unsafe_slice([0 x i16]* nonnull %arg0.0, [[USIZE]] %arg0.1)
// CHECK: @unsafe_slice([0 x i16]* nonnull align 2 %arg0.0, [[USIZE]] %arg0.1)
// unsafe interior means this isn't actually readonly and there may be aliases ...
#[no_mangle]
pub fn unsafe_slice(_: &[UnsafeInner]) {
}
// CHECK: @str([0 x i8]* noalias nonnull readonly %arg0.0, [[USIZE]] %arg0.1)
// CHECK: @str([0 x i8]* noalias nonnull readonly align 1 %arg0.0, [[USIZE]] %arg0.1)
// FIXME #25759 This should also have `nocapture`
#[no_mangle]
pub fn str(_: &[u8]) {
}
// CHECK: @trait_borrow({}* nonnull %arg0.0, [3 x [[USIZE]]]* noalias readonly dereferenceable({{.*}}) %arg0.1)
// CHECK: @trait_borrow({}* nonnull align 1 %arg0.0, [3 x [[USIZE]]]* noalias readonly align {{.*}} dereferenceable({{.*}}) %arg0.1)
// FIXME #25759 This should also have `nocapture`
#[no_mangle]
pub fn trait_borrow(_: &Drop) {
}
// CHECK: @trait_box({}* noalias nonnull, [3 x [[USIZE]]]* noalias readonly dereferenceable({{.*}}))
// CHECK: @trait_box({}* noalias nonnull align 1, [3 x [[USIZE]]]* noalias readonly align {{.*}} dereferenceable({{.*}}))
#[no_mangle]
pub fn trait_box(_: Box<Drop>) {
}
// CHECK: { i8*, i8* } @trait_option(i8* noalias %x.0, i8* %x.1)
// CHECK: { i8*, i8* } @trait_option(i8* noalias align 1 %x.0, i8* %x.1)
#[no_mangle]
pub fn trait_option(x: Option<Box<Drop>>) -> Option<Box<Drop>> {
x
}
// CHECK: { [0 x i16]*, [[USIZE]] } @return_slice([0 x i16]* noalias nonnull readonly %x.0, [[USIZE]] %x.1)
// CHECK: { [0 x i16]*, [[USIZE]] } @return_slice([0 x i16]* noalias nonnull readonly align 2 %x.0, [[USIZE]] %x.1)
#[no_mangle]
pub fn return_slice(x: &[u16]) -> &[u16] {
x

View File

@ -1,28 +0,0 @@
-include ../tools.mk
ifeq ($(UNAME),Darwin)
PLUGIN_FLAGS := -C link-args=-Wl,-undefined,dynamic_lookup
endif
ifeq ($(findstring stage1,$(RUST_BUILD_STAGE)),stage1)
# ignore stage1
all:
else
# Windows doesn't correctly handle include statements with escaping paths,
# so this test will not get run on Windows.
ifdef IS_WINDOWS
all:
else
all: $(call NATIVE_STATICLIB,llvm-function-pass) $(call NATIVE_STATICLIB,llvm-module-pass)
$(RUSTC) plugin.rs -C prefer-dynamic $(PLUGIN_FLAGS)
$(RUSTC) main.rs
$(TMPDIR)/libllvm-function-pass.o:
$(CXX) $(CFLAGS) $(LLVM_CXXFLAGS) -c llvm-function-pass.so.cc -o $(TMPDIR)/libllvm-function-pass.o
$(TMPDIR)/libllvm-module-pass.o:
$(CXX) $(CFLAGS) $(LLVM_CXXFLAGS) -c llvm-module-pass.so.cc -o $(TMPDIR)/libllvm-module-pass.o
endif
endif

View File

@ -1,56 +0,0 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
using namespace llvm;
namespace {
class TestLLVMPass : public FunctionPass {
public:
static char ID;
TestLLVMPass() : FunctionPass(ID) { }
bool runOnFunction(Function &F) override;
StringRef getPassName() const override {
return "Some LLVM pass";
}
};
}
bool TestLLVMPass::runOnFunction(Function &F) {
// A couple examples of operations that previously caused segmentation faults
// https://github.com/rust-lang/rust/issues/31067
for (auto N = F.begin(); N != F.end(); ++N) {
/* code */
}
LLVMContext &C = F.getContext();
IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
PointerType::get(Int8Ty, 0);
return true;
}
char TestLLVMPass::ID = 0;
static RegisterPass<TestLLVMPass> RegisterAFLPass(
"some-llvm-function-pass", "Some LLVM pass");

View File

@ -1,55 +0,0 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "llvm/IR/Module.h"
using namespace llvm;
namespace {
class TestLLVMPass : public ModulePass {
public:
static char ID;
TestLLVMPass() : ModulePass(ID) { }
bool runOnModule(Module &M) override;
StringRef getPassName() const override {
return "Some LLVM pass";
}
};
}
bool TestLLVMPass::runOnModule(Module &M) {
// A couple examples of operations that previously caused segmentation faults
// https://github.com/rust-lang/rust/issues/31067
for (auto F = M.begin(); F != M.end(); ++F) {
/* code */
}
LLVMContext &C = M.getContext();
IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
PointerType::get(Int8Ty, 0);
return true;
}
char TestLLVMPass::ID = 0;
static RegisterPass<TestLLVMPass> RegisterAFLPass(
"some-llvm-module-pass", "Some LLVM pass");

View File

@ -1,14 +0,0 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(plugin)]
#![plugin(some_plugin)]
fn main() {}

View File

@ -1,28 +0,0 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(plugin_registrar, rustc_private)]
#![crate_type = "dylib"]
#![crate_name = "some_plugin"]
extern crate rustc;
extern crate rustc_plugin;
#[link(name = "llvm-function-pass", kind = "static")]
#[link(name = "llvm-module-pass", kind = "static")]
extern {}
use rustc_plugin::registry::Registry;
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
reg.register_llvm_pass("some-llvm-function-pass");
reg.register_llvm_pass("some-llvm-module-pass");
}