]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #808 - RalfJung:extra-fn, r=RalfJung
authorbors <bors@rust-lang.org>
Sat, 6 Jul 2019 08:26:10 +0000 (08:26 +0000)
committerbors <bors@rust-lang.org>
Sat, 6 Jul 2019 08:26:10 +0000 (08:26 +0000)
use Dlsym support to implement getentropy (and better thread spawn error)

This is the Miri side of https://github.com/rust-lang/rust/pull/62245.

Fixes https://github.com/rust-lang/miri/issues/789

rust-version
src/eval.rs
src/helpers.rs
src/lib.rs
src/machine.rs
src/shims/dlsym.rs [new file with mode: 0644]
src/shims/foreign_items.rs
src/shims/mod.rs
test-cargo-miri/Cargo.lock
tests/compile-fail/thread-spawn.rs [new file with mode: 0644]

index e278a80633709871261c1b526a6a9fc1ef8a0824..e70f05a0090dd1edabc686b1993fe5795b614ed3 100644 (file)
@@ -1 +1 @@
-481068a707679257e2a738b40987246e0420e787
+b820c761744db080ff7a4ba3ac88d259065cb836
index 6132c502531fa5c919b49083d8d39fe03f19b254..bf99d3e61166b2069f56c740cbff7760e3aedfee 100644 (file)
@@ -11,7 +11,7 @@
 
 use crate::{
     InterpResult, InterpError, InterpCx, StackPopCleanup, struct_error,
-    Scalar, Tag, Pointer,
+    Scalar, Tag, Pointer, FnVal,
     MemoryExtra, MiriMemoryKind, Evaluator, TlsEvalContextExt,
 };
 
@@ -93,7 +93,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
     let mut args = ecx.frame().body.args_iter();
 
     // First argument: pointer to `main()`.
-    let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance);
+    let main_ptr = ecx.memory_mut().create_fn_alloc(FnVal::Instance(main_instance));
     let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?;
     ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?;
 
index 3503af43690f996fc3e02ba57dfe51840bac2153..b9fa7bc2a77a4951f35ad11969e84fe507b2b526 100644 (file)
@@ -1,8 +1,10 @@
 use std::mem;
 
-use rustc::ty::{self, layout::{self, Size}};
+use rustc::ty::{self, layout::{self, Size, Align}};
 use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX};
 
+use rand::RngCore;
+
 use crate::*;
 
 impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
@@ -65,6 +67,40 @@ fn test_null(&self, val: Scalar<Tag>) -> InterpResult<'tcx, Option<Scalar<Tag>>>
         })
     }
 
+    /// Generate some random bytes, and write them to `dest`.
+    fn gen_random(
+        &mut self,
+        len: usize,
+        ptr: Scalar<Tag>,
+    ) -> InterpResult<'tcx>  {
+        let this = self.eval_context_mut();
+
+        let ptr = match this.memory().check_ptr_access(ptr, Size::from_bytes(len as u64), Align::from_bytes(1).unwrap())? {
+            Some(ptr) => ptr,
+            None => return Ok(()), // zero-sized access
+        };
+
+        let data = match &mut this.memory_mut().extra.rng {
+            Some(rng) => {
+                let mut rng = rng.borrow_mut();
+                let mut data = vec![0; len];
+                rng.fill_bytes(&mut data);
+                data
+            }
+            None => {
+                return err!(Unimplemented(
+                    "miri does not support gathering system entropy in deterministic mode!
+                    Use '-Zmiri-seed=<seed>' to enable random number generation.
+                    WARNING: Miri does *not* generate cryptographically secure entropy -
+                    do not use Miri to run any program that needs secure random number generation".to_owned(),
+                ));
+            }
+        };
+        let tcx = &{this.tcx.tcx};
+        this.memory_mut().get_mut(ptr.alloc_id)?
+            .write_bytes(tcx, ptr, &data)
+    }
+
     /// Visits the memory covered by `place`, sensitive to freezing: the 3rd parameter
     /// will be true if this is frozen, false if this is in an `UnsafeCell`.
     fn visit_freeze_sensitive(
index 31e707077769c6f2b92525fa51e069ab60fa8d35..20c24ad54fe846a62b4fd89fd3963b3c53f3d576 100644 (file)
 pub use crate::shims::foreign_items::EvalContextExt as ForeignItemsEvalContextExt;
 pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt;
 pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData};
+pub use crate::shims::dlsym::{Dlsym, EvalContextExt as DlsymEvalContextExt};
 pub use crate::operator::EvalContextExt as OperatorEvalContextExt;
 pub use crate::range_map::RangeMap;
 pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt};
 pub use crate::mono_hash_map::MonoHashMap;
 pub use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt, Tag, Permission, Stack, Stacks, Item};
 pub use crate::machine::{
-    PAGE_SIZE, STACK_ADDR, NUM_CPUS,
+    PAGE_SIZE, STACK_ADDR, STACK_SIZE, NUM_CPUS,
     MemoryExtra, AllocExtra, MiriMemoryKind, Evaluator, MiriEvalContext, MiriEvalContextExt,
 };
 pub use crate::eval::{eval_main, create_ecx, MiriConfig};
index 0875331131bd34dd9ccdf0c42851b88dd0fbf36f..d1cf913a75bfd9c1e07618579b36fa7ce12ec66e 100644 (file)
 use syntax::attr;
 use syntax::symbol::sym;
 use rustc::hir::def_id::DefId;
-use rustc::ty::{self, layout::{Size, LayoutOf}, query::TyCtxtAt};
+use rustc::ty::{self, layout::{Size, LayoutOf}, TyCtxt};
 use rustc::mir;
 
 use crate::*;
 
 // Some global facts about the emulated machine.
 pub const PAGE_SIZE: u64 = 4*1024; // FIXME: adjust to target architecture
-pub const STACK_ADDR: u64 = 16*PAGE_SIZE; // not really about the "stack", but where we start assigning integer addresses to allocations
+pub const STACK_ADDR: u64 = 32*PAGE_SIZE; // not really about the "stack", but where we start assigning integer addresses to allocations
+pub const STACK_SIZE: u64 = 16*PAGE_SIZE; // whatever
 pub const NUM_CPUS: u64 = 1;
 
 /// Extra memory kinds
@@ -135,6 +136,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> {
     type MemoryExtra = MemoryExtra;
     type AllocExtra = AllocExtra;
     type PointerTag = Tag;
+    type ExtraFnVal = Dlsym;
 
     type MemoryMap = MonoHashMap<AllocId, (MemoryKind<MiriMemoryKind>, Allocation<Tag, Self::AllocExtra>)>;
 
@@ -145,7 +147,6 @@ fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
         ecx.memory().extra.validate
     }
 
-    /// Returns `Ok()` when the function was handled; fail otherwise.
     #[inline(always)]
     fn find_fn(
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
@@ -157,6 +158,17 @@ fn find_fn(
         ecx.find_fn(instance, args, dest, ret)
     }
 
+    #[inline(always)]
+    fn call_extra_fn(
+        ecx: &mut InterpCx<'mir, 'tcx, Self>,
+        fn_val: Dlsym,
+        args: &[OpTy<'tcx, Tag>],
+        dest: Option<PlaceTy<'tcx, Tag>>,
+        ret: Option<mir::BasicBlock>,
+    ) -> InterpResult<'tcx> {
+        ecx.call_dlsym(fn_val, args, dest, ret)
+    }
+
     #[inline(always)]
     fn call_intrinsic(
         ecx: &mut rustc_mir::interpret::InterpCx<'mir, 'tcx, Self>,
@@ -220,8 +232,8 @@ fn box_alloc(
     }
 
     fn find_foreign_static(
+        tcx: TyCtxt<'tcx>,
         def_id: DefId,
-        tcx: TyCtxtAt<'tcx>,
     ) -> InterpResult<'tcx, Cow<'tcx, Allocation>> {
         let attrs = tcx.get_attrs(def_id);
         let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) {
@@ -251,20 +263,20 @@ fn before_terminator(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx
     }
 
     fn tag_allocation<'b>(
+        memory_extra: &MemoryExtra,
         id: AllocId,
         alloc: Cow<'b, Allocation>,
         kind: Option<MemoryKind<Self::MemoryKinds>>,
-        memory: &Memory<'mir, 'tcx, Self>,
     ) -> (Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>>, Self::PointerTag) {
         let kind = kind.expect("we set our STATIC_KIND so this cannot be None");
         let alloc = alloc.into_owned();
-        let (stacks, base_tag) = if !memory.extra.validate {
+        let (stacks, base_tag) = if !memory_extra.validate {
             (None, Tag::Untagged)
         } else {
             let (stacks, base_tag) = Stacks::new_allocation(
                 id,
                 Size::from_bytes(alloc.bytes.len() as u64),
-                Rc::clone(&memory.extra.stacked_borrows),
+                Rc::clone(&memory_extra.stacked_borrows),
                 kind,
             );
             (Some(stacks), base_tag)
@@ -273,7 +285,7 @@ fn tag_allocation<'b>(
             assert!(alloc.relocations.is_empty(), "Only statics can come initialized with inner pointers");
             // Now we can rely on the inner pointers being static, too.
         }
-        let mut memory_extra = memory.extra.stacked_borrows.borrow_mut();
+        let mut stacked_borrows = memory_extra.stacked_borrows.borrow_mut();
         let alloc: Allocation<Tag, Self::AllocExtra> = Allocation {
             bytes: alloc.bytes,
             relocations: Relocations::from_presorted(
@@ -281,10 +293,10 @@ fn tag_allocation<'b>(
                     // The allocations in the relocations (pointers stored *inside* this allocation)
                     // all get the base pointer tag.
                     .map(|&(offset, ((), alloc))| {
-                        let tag = if !memory.extra.validate {
+                        let tag = if !memory_extra.validate {
                             Tag::Untagged
                         } else {
-                            memory_extra.static_base_ptr(alloc)
+                            stacked_borrows.static_base_ptr(alloc)
                         };
                         (offset, (tag, alloc))
                     })
@@ -302,13 +314,13 @@ fn tag_allocation<'b>(
 
     #[inline(always)]
     fn tag_static_base_pointer(
+        memory_extra: &MemoryExtra,
         id: AllocId,
-        memory: &Memory<'mir, 'tcx, Self>,
     ) -> Self::PointerTag {
-        if !memory.extra.validate {
+        if !memory_extra.validate {
             Tag::Untagged
         } else {
-            memory.extra.stacked_borrows.borrow_mut().static_base_ptr(id)
+            memory_extra.stacked_borrows.borrow_mut().static_base_ptr(id)
         }
     }
 
@@ -342,8 +354,8 @@ fn stack_pop(
     }
 
     fn int_to_ptr(
-        int: u64,
         memory: &Memory<'mir, 'tcx, Self>,
+        int: u64,
     ) -> InterpResult<'tcx, Pointer<Self::PointerTag>> {
         if int == 0 {
             err!(InvalidNullPointerUsage)
@@ -355,8 +367,8 @@ fn int_to_ptr(
     }
 
     fn ptr_to_int(
-        ptr: Pointer<Self::PointerTag>,
         memory: &Memory<'mir, 'tcx, Self>,
+        ptr: Pointer<Self::PointerTag>,
     ) -> InterpResult<'tcx, u64> {
         if memory.extra.rng.is_none() {
             err!(ReadPointerAsBytes)
diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs
new file mode 100644 (file)
index 0000000..602d806
--- /dev/null
@@ -0,0 +1,55 @@
+use rustc::mir;
+
+use crate::*;
+
+#[derive(Debug, Copy, Clone)]
+pub enum Dlsym {
+    GetEntropy,
+}
+
+impl Dlsym {
+    // Returns an error for unsupported symbols, and None if this symbol
+    // should become a NULL pointer (pretend it does not exist).
+    pub fn from_str(name: &str) -> InterpResult<'static, Option<Dlsym>> {
+        use self::Dlsym::*;
+        Ok(match name {
+            "getentropy" => Some(GetEntropy),
+            "__pthread_get_minstack" => None,
+            _ =>
+                return err!(Unimplemented(format!(
+                    "Unsupported dlsym: {}", name
+                ))),
+        })
+    }
+}
+
+impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
+pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
+    fn call_dlsym(
+        &mut self,
+        dlsym: Dlsym,
+        args: &[OpTy<'tcx, Tag>],
+        dest: Option<PlaceTy<'tcx, Tag>>,
+        ret: Option<mir::BasicBlock>,
+    ) -> InterpResult<'tcx> {
+        use self::Dlsym::*;
+
+        let this = self.eval_context_mut();
+
+        let dest = dest.expect("we don't support any diverging dlsym");
+        let ret = ret.expect("dest is `Some` but ret is `None`");
+
+        match dlsym {
+            GetEntropy => {
+                let ptr = this.read_scalar(args[0])?.not_undef()?;
+                let len = this.read_scalar(args[1])?.to_usize(this)?;
+                this.gen_random(len as usize, ptr)?;
+                this.write_null(dest)?;
+            }
+        }
+
+        this.goto_block(Some(ret))?;
+        this.dump_place(*dest);
+        Ok(())
+    }
+}
index 2fe2ecc19581aacdc1e29ae6d9b91b80e31af73d..9dbb55668ef35dc707ab4fdbce71e8877250a7eb 100644 (file)
@@ -4,8 +4,6 @@
 use syntax::attr;
 use syntax::symbol::sym;
 
-use rand::RngCore;
-
 use crate::*;
 
 impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
@@ -307,7 +305,7 @@ fn emulate_foreign_item(
                         // neither of which have any effect on our current PRNG
                         let _flags = this.read_scalar(args[3])?.to_i32()?;
 
-                        gen_random(this, len as usize, ptr)?;
+                        this.gen_random(len as usize, ptr)?;
                         this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?;
                     }
                     id => {
@@ -324,10 +322,12 @@ fn emulate_foreign_item(
                 let symbol_name = this.memory().get(symbol.alloc_id)?.read_c_str(tcx, symbol)?;
                 let err = format!("bad c unicode symbol: {:?}", symbol_name);
                 let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err);
-                return err!(Unimplemented(format!(
-                    "miri does not support dynamically loading libraries (requested symbol: {})",
-                    symbol_name
-                )));
+                if let Some(dlsym) = Dlsym::from_str(symbol_name)? {
+                    let ptr = this.memory_mut().create_fn_alloc(FnVal::Other(dlsym));
+                    this.write_scalar(Scalar::from(ptr), dest)?;
+                } else {
+                    this.write_null(dest)?;
+                }
             }
 
             "__rust_maybe_catch_panic" => {
@@ -338,9 +338,9 @@ fn emulate_foreign_item(
                 //     vtable_ptr: *mut usize,
                 // ) -> u32
                 // We abort on panic, so not much is going on here, but we still have to call the closure.
-                let f = this.read_scalar(args[0])?.to_ptr()?;
+                let f = this.read_scalar(args[0])?.not_undef()?;
                 let data = this.read_scalar(args[1])?.not_undef()?;
-                let f_instance = this.memory().get_fn(f)?;
+                let f_instance = this.memory().get_fn(f)?.as_instance()?;
                 this.write_null(dest)?;
                 trace!("__rust_maybe_catch_panic: {:?}", f_instance);
 
@@ -659,7 +659,7 @@ fn emulate_foreign_item(
 
                 // Extract the function type out of the signature (that seems easier than constructing it ourselves).
                 let dtor = match this.test_null(this.read_scalar(args[1])?.not_undef()?)? {
-                    Some(dtor_ptr) => Some(this.memory().get_fn(dtor_ptr.to_ptr()?)?),
+                    Some(dtor_ptr) => Some(this.memory().get_fn(dtor_ptr)?.as_instance()?),
                     None => None,
                 };
 
@@ -709,24 +709,31 @@ fn emulate_foreign_item(
                 this.write_null(dest)?;
             }
 
-            // Determine stack base address.
-            "pthread_attr_init" | "pthread_attr_destroy" | "pthread_attr_get_np" |
-            "pthread_getattr_np" | "pthread_self" | "pthread_get_stacksize_np" => {
+            // Stack size/address stuff.
+            "pthread_attr_init" | "pthread_attr_destroy" | "pthread_self" |
+            "pthread_attr_setstacksize" => {
                 this.write_null(dest)?;
             }
             "pthread_attr_getstack" => {
-                // Second argument is where we are supposed to write the stack size.
-                let ptr = this.deref_operand(args[1])?;
-                // Just any address.
-                let stack_addr = Scalar::from_uint(STACK_ADDR, args[1].layout.size);
-                this.write_scalar(stack_addr, ptr.into())?;
+                let addr_place = this.deref_operand(args[1])?;
+                let size_place = this.deref_operand(args[2])?;
+
+                this.write_scalar(
+                    Scalar::from_uint(STACK_ADDR, addr_place.layout.size),
+                    addr_place.into(),
+                )?;
+                this.write_scalar(
+                    Scalar::from_uint(STACK_SIZE, size_place.layout.size),
+                    size_place.into(),
+                )?;
+
                 // Return success (`0`).
                 this.write_null(dest)?;
             }
-            "pthread_get_stackaddr_np" => {
-                // Just any address.
-                let stack_addr = Scalar::from_uint(STACK_ADDR, dest.layout.size);
-                this.write_scalar(stack_addr, dest)?;
+
+            // We don't support threading.
+            "pthread_create" => {
+                return err!(Unimplemented(format!("Miri does not support threading")));
             }
 
             // Stub out calls for condvar, mutex and rwlock, to just return `0`.
@@ -754,6 +761,17 @@ fn emulate_foreign_item(
             }
 
             // macOS API stubs.
+            "pthread_attr_get_np" | "pthread_getattr_np" => {
+                this.write_null(dest)?;
+            }
+            "pthread_get_stackaddr_np" => {
+                let stack_addr = Scalar::from_uint(STACK_ADDR, dest.layout.size);
+                this.write_scalar(stack_addr, dest)?;
+            }
+            "pthread_get_stacksize_np" => {
+                let stack_size = Scalar::from_uint(STACK_SIZE, dest.layout.size);
+                this.write_scalar(stack_size, dest)?;
+            }
             "_tlv_atexit" => {
                 // FIXME: register the destructor.
             },
@@ -766,7 +784,7 @@ fn emulate_foreign_item(
             "SecRandomCopyBytes" => {
                 let len = this.read_scalar(args[1])?.to_usize(this)?;
                 let ptr = this.read_scalar(args[2])?.not_undef()?;
-                gen_random(this, len as usize, ptr)?;
+                this.gen_random(len as usize, ptr)?;
                 this.write_null(dest)?;
             }
 
@@ -934,7 +952,7 @@ fn emulate_foreign_item(
             "SystemFunction036" => {
                 let ptr = this.read_scalar(args[0])?.not_undef()?;
                 let len = this.read_scalar(args[1])?.to_u32()?;
-                gen_random(this, len as usize, ptr)?;
+                this.gen_random(len as usize, ptr)?;
                 this.write_scalar(Scalar::from_bool(true), dest)?;
             }
 
@@ -966,36 +984,4 @@ fn eval_path_scalar(&mut self, path: &[&str]) -> InterpResult<'tcx, Option<Scala
         }
         return Ok(None);
     }
-}
-
-fn gen_random<'mir, 'tcx>(
-    this: &mut MiriEvalContext<'mir, 'tcx>,
-    len: usize,
-    dest: Scalar<Tag>,
-) -> InterpResult<'tcx>  {
-    if len == 0 {
-        // Nothing to do
-        return Ok(());
-    }
-    let ptr = dest.to_ptr()?;
-
-    let data = match &mut this.memory_mut().extra.rng {
-        Some(rng) => {
-            let mut rng = rng.borrow_mut();
-            let mut data = vec![0; len];
-            rng.fill_bytes(&mut data);
-            data
-        }
-        None => {
-            return err!(Unimplemented(
-                "miri does not support gathering system entropy in deterministic mode!
-                Use '-Zmiri-seed=<seed>' to enable random number generation.
-                WARNING: Miri does *not* generate cryptographically secure entropy -
-                do not use Miri to run any program that needs secure random number generation".to_owned(),
-            ));
-        }
-    };
-    let tcx = &{this.tcx.tcx};
-    this.memory_mut().get_mut(ptr.alloc_id)?
-        .write_bytes(tcx, ptr, &data)
-}
+}
\ No newline at end of file
index 3258cf3d9c1da6ea8c9b45f831aa6becc23fd198..c06373005ff9919155009afa5b2f1964f37da7e4 100644 (file)
@@ -1,6 +1,7 @@
 pub mod foreign_items;
 pub mod intrinsics;
 pub mod tls;
+pub mod dlsym;
 
 use rustc::{ty, mir};
 
index 8343832886a6b3adc8aa7ce1d04dace1d925f172..55e5a3dfc185db436482aa8baffb9dea1b609a55 100644 (file)
@@ -5,11 +5,6 @@ name = "autocfg"
 version = "0.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
-[[package]]
-name = "bitflags"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
 [[package]]
 name = "byteorder"
 version = "1.3.2"
@@ -33,34 +28,22 @@ dependencies = [
  "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
-[[package]]
-name = "cloudabi"
-version = "0.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "fuchsia-cprng"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
 [[package]]
 name = "getrandom"
-version = "0.1.3"
+version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "lazy_static"
 version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
 
 [[package]]
 name = "libc"
@@ -85,7 +68,7 @@ name = "rand"
 version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand_chacha 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -108,7 +91,7 @@ name = "rand_core"
 version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -129,32 +112,15 @@ dependencies = [
 ]
 
 [[package]]
-name = "winapi"
-version = "0.3.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "winapi-i686-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "winapi-x86_64-pc-windows-gnu"
-version = "0.4.0"
+name = "spin"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [metadata]
 "checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf"
-"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"
 "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
 "checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101"
-"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
-"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
-"checksum getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8d1dffef07351aafe6ef177e4dd2b8dcf503e6bc765dea3b0de9ed149a3db1ec"
+"checksum getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e65cce4e5084b14874c4e7097f38cab54f47ee554f9194673456ea379dcc4c55"
 "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
 "checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319"
 "checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273"
@@ -164,6 +130,4 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca"
 "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
 "checksum rand_pcg 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e196346cbbc5c70c77e7b4926147ee8e383a38ee4d15d58a08098b169e492b6"
-"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"
-"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
-"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+"checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55"
diff --git a/tests/compile-fail/thread-spawn.rs b/tests/compile-fail/thread-spawn.rs
new file mode 100644 (file)
index 0000000..450dea9
--- /dev/null
@@ -0,0 +1,7 @@
+use std::thread;
+
+// error-pattern: Miri does not support threading
+
+fn main() {
+    thread::spawn(|| {});
+}