diff --git a/.travis.yml b/.travis.yml index d37cc4b..4697a97 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,12 +1,7 @@ language: rust rust: - - nightly-2018-06-09 - - nightly - -matrix: - allow_failures: - - rust: nightly + - nightly-2018-08-18 install: - set -eo pipefail diff --git a/ctr-std/src/alloc.rs b/ctr-std/src/alloc.rs index 3b1a3a4..b9aba1e 100644 --- a/ctr-std/src/alloc.rs +++ b/ctr-std/src/alloc.rs @@ -8,61 +8,129 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! dox +//! Memory allocation APIs +//! +//! In a given program, the standard library has one “global” memory allocator +//! that is used for example by `Box` and `Vec`. +//! +//! Currently the default global allocator is unspecified. +//! The compiler may link to a version of [jemalloc] on some platforms, +//! but this is not guaranteed. +//! Libraries, however, like `cdylib`s and `staticlib`s are guaranteed +//! to use the [`System`] by default. +//! +//! [jemalloc]: https://github.com/jemalloc/jemalloc +//! [`System`]: struct.System.html +//! +//! # The `#[global_allocator]` attribute +//! +//! This attribute allows configuring the choice of global allocator. +//! You can use this to implement a completely custom global allocator +//! to route all default allocation requests to a custom object. +//! +//! ```rust +//! use std::alloc::{GlobalAlloc, System, Layout}; +//! +//! struct MyAllocator; +//! +//! unsafe impl GlobalAlloc for MyAllocator { +//! unsafe fn alloc(&self, layout: Layout) -> *mut u8 { +//! System.alloc(layout) +//! } +//! +//! unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { +//! System.dealloc(ptr, layout) +//! } +//! } +//! +//! #[global_allocator] +//! static GLOBAL: MyAllocator = MyAllocator; +//! +//! fn main() { +//! // This `Vec` will allocate memory through `GLOBAL` above +//! let mut v = Vec::new(); +//! v.push(1); +//! } +//! ``` +//! +//! The attribute is used on a `static` item whose type implements the +//! [`GlobalAlloc`] trait. This type can be provided by an external library: +//! +//! [`GlobalAlloc`]: ../../core/alloc/trait.GlobalAlloc.html +//! +//! ```rust,ignore (demonstrates crates.io usage) +//! extern crate jemallocator; +//! +//! use jemallocator::Jemalloc; +//! +//! #[global_allocator] +//! static GLOBAL: Jemalloc = Jemalloc; +//! +//! fn main() {} +//! ``` +//! +//! The `#[global_allocator]` can only be used once in a crate +//! or its recursive dependencies. -#![unstable(issue = "32838", feature = "allocator_api")] - -#[doc(inline)] #[allow(deprecated)] pub use alloc_crate::alloc::Heap; -#[doc(inline)] pub use alloc_crate::alloc::{Global, Layout, oom}; -#[doc(inline)] pub use alloc_system::System; -#[doc(inline)] pub use core::alloc::*; +#![stable(feature = "alloc_module", since = "1.28.0")] use core::sync::atomic::{AtomicPtr, Ordering}; use core::{mem, ptr}; use sys_common::util::dumb_print; +#[stable(feature = "alloc_module", since = "1.28.0")] +#[doc(inline)] +pub use alloc_crate::alloc::*; + +#[stable(feature = "alloc_system_type", since = "1.28.0")] +#[doc(inline)] +pub use alloc_system::System; + static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut()); -/// Registers a custom OOM hook, replacing any that was previously registered. +/// Registers a custom allocation error hook, replacing any that was previously registered. /// -/// The OOM hook is invoked when an infallible memory allocation fails, before +/// The allocation error hook is invoked when an infallible memory allocation fails, before /// the runtime aborts. The default hook prints a message to standard error, -/// but this behavior can be customized with the [`set_oom_hook`] and -/// [`take_oom_hook`] functions. +/// but this behavior can be customized with the [`set_alloc_error_hook`] and +/// [`take_alloc_error_hook`] functions. /// /// The hook is provided with a `Layout` struct which contains information /// about the allocation that failed. /// -/// The OOM hook is a global resource. -pub fn set_oom_hook(hook: fn(Layout)) { +/// The allocation error hook is a global resource. +#[unstable(feature = "alloc_error_hook", issue = "51245")] +pub fn set_alloc_error_hook(hook: fn(Layout)) { HOOK.store(hook as *mut (), Ordering::SeqCst); } -/// Unregisters the current OOM hook, returning it. +/// Unregisters the current allocation error hook, returning it. /// -/// *See also the function [`set_oom_hook`].* +/// *See also the function [`set_alloc_error_hook`].* /// /// If no custom hook is registered, the default hook will be returned. -pub fn take_oom_hook() -> fn(Layout) { +#[unstable(feature = "alloc_error_hook", issue = "51245")] +pub fn take_alloc_error_hook() -> fn(Layout) { let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst); if hook.is_null() { - default_oom_hook + default_alloc_error_hook } else { unsafe { mem::transmute(hook) } } } -fn default_oom_hook(layout: Layout) { +fn default_alloc_error_hook(layout: Layout) { dumb_print(format_args!("memory allocation of {} bytes failed", layout.size())); } #[cfg(not(test))] #[doc(hidden)] -#[lang = "oom"] -pub extern fn rust_oom(layout: Layout) -> ! { +#[alloc_error_handler] +#[unstable(feature = "alloc_internals", issue = "0")] +pub fn rust_oom(layout: Layout) -> ! { let hook = HOOK.load(Ordering::SeqCst); let hook: fn(Layout) = if hook.is_null() { - default_oom_hook + default_alloc_error_hook } else { unsafe { mem::transmute(hook) } }; @@ -73,8 +141,9 @@ pub extern fn rust_oom(layout: Layout) -> ! { #[cfg(not(test))] #[doc(hidden)] #[allow(unused_attributes)] +#[unstable(feature = "alloc_internals", issue = "0")] pub mod __default_lib_allocator { - use super::{System, Layout, GlobalAlloc, Opaque}; + use super::{System, Layout, GlobalAlloc}; // for symbol names src/librustc/middle/allocator.rs // for signatures src/librustc_allocator/lib.rs @@ -85,7 +154,7 @@ pub mod __default_lib_allocator { #[rustc_std_internal_symbol] pub unsafe extern fn __rdl_alloc(size: usize, align: usize) -> *mut u8 { let layout = Layout::from_size_align_unchecked(size, align); - System.alloc(layout) as *mut u8 + System.alloc(layout) } #[no_mangle] @@ -93,7 +162,7 @@ pub mod __default_lib_allocator { pub unsafe extern fn __rdl_dealloc(ptr: *mut u8, size: usize, align: usize) { - System.dealloc(ptr as *mut Opaque, Layout::from_size_align_unchecked(size, align)) + System.dealloc(ptr, Layout::from_size_align_unchecked(size, align)) } #[no_mangle] @@ -103,13 +172,13 @@ pub mod __default_lib_allocator { align: usize, new_size: usize) -> *mut u8 { let old_layout = Layout::from_size_align_unchecked(old_size, align); - System.realloc(ptr as *mut Opaque, old_layout, new_size) as *mut u8 + System.realloc(ptr, old_layout, new_size) } #[no_mangle] #[rustc_std_internal_symbol] pub unsafe extern fn __rdl_alloc_zeroed(size: usize, align: usize) -> *mut u8 { let layout = Layout::from_size_align_unchecked(size, align); - System.alloc_zeroed(layout) as *mut u8 + System.alloc_zeroed(layout) } } diff --git a/ctr-std/src/ascii.rs b/ctr-std/src/ascii.rs index 6472edb..0c8e95a 100644 --- a/ctr-std/src/ascii.rs +++ b/ctr-std/src/ascii.rs @@ -154,160 +154,6 @@ pub trait AsciiExt { /// [`to_ascii_lowercase`]: #tymethod.to_ascii_lowercase #[stable(feature = "ascii", since = "1.9.0")] fn make_ascii_lowercase(&mut self); - - /// Checks if the value is an ASCII alphabetic character: - /// U+0041 'A' ... U+005A 'Z' or U+0061 'a' ... U+007A 'z'. - /// For strings, true if all characters in the string are - /// ASCII alphabetic. - /// - /// # Note - /// - /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. - #[unstable(feature = "ascii_ctype", issue = "39658")] - #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] - fn is_ascii_alphabetic(&self) -> bool { unimplemented!(); } - - /// Checks if the value is an ASCII uppercase character: - /// U+0041 'A' ... U+005A 'Z'. - /// For strings, true if all characters in the string are - /// ASCII uppercase. - /// - /// # Note - /// - /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. - #[unstable(feature = "ascii_ctype", issue = "39658")] - #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] - fn is_ascii_uppercase(&self) -> bool { unimplemented!(); } - - /// Checks if the value is an ASCII lowercase character: - /// U+0061 'a' ... U+007A 'z'. - /// For strings, true if all characters in the string are - /// ASCII lowercase. - /// - /// # Note - /// - /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. - #[unstable(feature = "ascii_ctype", issue = "39658")] - #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] - fn is_ascii_lowercase(&self) -> bool { unimplemented!(); } - - /// Checks if the value is an ASCII alphanumeric character: - /// U+0041 'A' ... U+005A 'Z', U+0061 'a' ... U+007A 'z', or - /// U+0030 '0' ... U+0039 '9'. - /// For strings, true if all characters in the string are - /// ASCII alphanumeric. - /// - /// # Note - /// - /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. - #[unstable(feature = "ascii_ctype", issue = "39658")] - #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] - fn is_ascii_alphanumeric(&self) -> bool { unimplemented!(); } - - /// Checks if the value is an ASCII decimal digit: - /// U+0030 '0' ... U+0039 '9'. - /// For strings, true if all characters in the string are - /// ASCII digits. - /// - /// # Note - /// - /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. - #[unstable(feature = "ascii_ctype", issue = "39658")] - #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] - fn is_ascii_digit(&self) -> bool { unimplemented!(); } - - /// Checks if the value is an ASCII hexadecimal digit: - /// U+0030 '0' ... U+0039 '9', U+0041 'A' ... U+0046 'F', or - /// U+0061 'a' ... U+0066 'f'. - /// For strings, true if all characters in the string are - /// ASCII hex digits. - /// - /// # Note - /// - /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. - #[unstable(feature = "ascii_ctype", issue = "39658")] - #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] - fn is_ascii_hexdigit(&self) -> bool { unimplemented!(); } - - /// Checks if the value is an ASCII punctuation character: - /// - /// U+0021 ... U+002F `! " # $ % & ' ( ) * + , - . /` - /// U+003A ... U+0040 `: ; < = > ? @` - /// U+005B ... U+0060 ``[ \\ ] ^ _ ` `` - /// U+007B ... U+007E `{ | } ~` - /// - /// For strings, true if all characters in the string are - /// ASCII punctuation. - /// - /// # Note - /// - /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. - #[unstable(feature = "ascii_ctype", issue = "39658")] - #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] - fn is_ascii_punctuation(&self) -> bool { unimplemented!(); } - - /// Checks if the value is an ASCII graphic character: - /// U+0021 '!' ... U+007E '~'. - /// For strings, true if all characters in the string are - /// ASCII graphic characters. - /// - /// # Note - /// - /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. - #[unstable(feature = "ascii_ctype", issue = "39658")] - #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] - fn is_ascii_graphic(&self) -> bool { unimplemented!(); } - - /// Checks if the value is an ASCII whitespace character: - /// U+0020 SPACE, U+0009 HORIZONTAL TAB, U+000A LINE FEED, - /// U+000C FORM FEED, or U+000D CARRIAGE RETURN. - /// For strings, true if all characters in the string are - /// ASCII whitespace. - /// - /// Rust uses the WhatWG Infra Standard's [definition of ASCII - /// whitespace][infra-aw]. There are several other definitions in - /// wide use. For instance, [the POSIX locale][pct] includes - /// U+000B VERTICAL TAB as well as all the above characters, - /// but—from the very same specification—[the default rule for - /// "field splitting" in the Bourne shell][bfs] considers *only* - /// SPACE, HORIZONTAL TAB, and LINE FEED as whitespace. - /// - /// If you are writing a program that will process an existing - /// file format, check what that format's definition of whitespace is - /// before using this function. - /// - /// [infra-aw]: https://infra.spec.whatwg.org/#ascii-whitespace - /// [pct]: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_01 - /// [bfs]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 - /// - /// # Note - /// - /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. - #[unstable(feature = "ascii_ctype", issue = "39658")] - #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] - fn is_ascii_whitespace(&self) -> bool { unimplemented!(); } - - /// Checks if the value is an ASCII control character: - /// U+0000 NUL ... U+001F UNIT SEPARATOR, or U+007F DELETE. - /// Note that most ASCII whitespace characters are control - /// characters, but SPACE is not. - /// - /// # Note - /// - /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. - #[unstable(feature = "ascii_ctype", issue = "39658")] - #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] - fn is_ascii_control(&self) -> bool { unimplemented!(); } } macro_rules! delegating_ascii_methods { @@ -332,47 +178,12 @@ macro_rules! delegating_ascii_methods { } } -macro_rules! delegating_ascii_ctype_methods { - () => { - #[inline] - fn is_ascii_alphabetic(&self) -> bool { self.is_ascii_alphabetic() } - - #[inline] - fn is_ascii_uppercase(&self) -> bool { self.is_ascii_uppercase() } - - #[inline] - fn is_ascii_lowercase(&self) -> bool { self.is_ascii_lowercase() } - - #[inline] - fn is_ascii_alphanumeric(&self) -> bool { self.is_ascii_alphanumeric() } - - #[inline] - fn is_ascii_digit(&self) -> bool { self.is_ascii_digit() } - - #[inline] - fn is_ascii_hexdigit(&self) -> bool { self.is_ascii_hexdigit() } - - #[inline] - fn is_ascii_punctuation(&self) -> bool { self.is_ascii_punctuation() } - - #[inline] - fn is_ascii_graphic(&self) -> bool { self.is_ascii_graphic() } - - #[inline] - fn is_ascii_whitespace(&self) -> bool { self.is_ascii_whitespace() } - - #[inline] - fn is_ascii_control(&self) -> bool { self.is_ascii_control() } - } -} - #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated)] impl AsciiExt for u8 { type Owned = u8; delegating_ascii_methods!(); - delegating_ascii_ctype_methods!(); } #[stable(feature = "rust1", since = "1.0.0")] @@ -381,7 +192,6 @@ impl AsciiExt for char { type Owned = char; delegating_ascii_methods!(); - delegating_ascii_ctype_methods!(); } #[stable(feature = "rust1", since = "1.0.0")] @@ -390,56 +200,6 @@ impl AsciiExt for [u8] { type Owned = Vec; delegating_ascii_methods!(); - - #[inline] - fn is_ascii_alphabetic(&self) -> bool { - self.iter().all(|b| b.is_ascii_alphabetic()) - } - - #[inline] - fn is_ascii_uppercase(&self) -> bool { - self.iter().all(|b| b.is_ascii_uppercase()) - } - - #[inline] - fn is_ascii_lowercase(&self) -> bool { - self.iter().all(|b| b.is_ascii_lowercase()) - } - - #[inline] - fn is_ascii_alphanumeric(&self) -> bool { - self.iter().all(|b| b.is_ascii_alphanumeric()) - } - - #[inline] - fn is_ascii_digit(&self) -> bool { - self.iter().all(|b| b.is_ascii_digit()) - } - - #[inline] - fn is_ascii_hexdigit(&self) -> bool { - self.iter().all(|b| b.is_ascii_hexdigit()) - } - - #[inline] - fn is_ascii_punctuation(&self) -> bool { - self.iter().all(|b| b.is_ascii_punctuation()) - } - - #[inline] - fn is_ascii_graphic(&self) -> bool { - self.iter().all(|b| b.is_ascii_graphic()) - } - - #[inline] - fn is_ascii_whitespace(&self) -> bool { - self.iter().all(|b| b.is_ascii_whitespace()) - } - - #[inline] - fn is_ascii_control(&self) -> bool { - self.iter().all(|b| b.is_ascii_control()) - } } #[stable(feature = "rust1", since = "1.0.0")] @@ -448,54 +208,4 @@ impl AsciiExt for str { type Owned = String; delegating_ascii_methods!(); - - #[inline] - fn is_ascii_alphabetic(&self) -> bool { - self.bytes().all(|b| b.is_ascii_alphabetic()) - } - - #[inline] - fn is_ascii_uppercase(&self) -> bool { - self.bytes().all(|b| b.is_ascii_uppercase()) - } - - #[inline] - fn is_ascii_lowercase(&self) -> bool { - self.bytes().all(|b| b.is_ascii_lowercase()) - } - - #[inline] - fn is_ascii_alphanumeric(&self) -> bool { - self.bytes().all(|b| b.is_ascii_alphanumeric()) - } - - #[inline] - fn is_ascii_digit(&self) -> bool { - self.bytes().all(|b| b.is_ascii_digit()) - } - - #[inline] - fn is_ascii_hexdigit(&self) -> bool { - self.bytes().all(|b| b.is_ascii_hexdigit()) - } - - #[inline] - fn is_ascii_punctuation(&self) -> bool { - self.bytes().all(|b| b.is_ascii_punctuation()) - } - - #[inline] - fn is_ascii_graphic(&self) -> bool { - self.bytes().all(|b| b.is_ascii_graphic()) - } - - #[inline] - fn is_ascii_whitespace(&self) -> bool { - self.bytes().all(|b| b.is_ascii_whitespace()) - } - - #[inline] - fn is_ascii_control(&self) -> bool { - self.bytes().all(|b| b.is_ascii_control()) - } } diff --git a/ctr-std/src/build.rs b/ctr-std/src/build.rs index c001e4e..016e7ad 100644 --- a/ctr-std/src/build.rs +++ b/ctr-std/src/build.rs @@ -22,7 +22,6 @@ fn main() { if cfg!(feature = "backtrace") && !target.contains("cloudabi") && !target.contains("emscripten") && - !target.contains("fuchsia") && !target.contains("msvc") && !target.contains("wasm32") { @@ -68,10 +67,6 @@ fn main() { println!("cargo:rustc-link-lib=userenv"); println!("cargo:rustc-link-lib=shell32"); } else if target.contains("fuchsia") { - // use system-provided libbacktrace - if cfg!(feature = "backtrace") { - println!("cargo:rustc-link-lib=backtrace"); - } println!("cargo:rustc-link-lib=zircon"); println!("cargo:rustc-link-lib=fdio"); } else if target.contains("cloudabi") { @@ -109,7 +104,8 @@ fn build_libbacktrace(target: &str) -> Result<(), ()> { } else { build.file("../libbacktrace/elf.c"); - if target.contains("64") { + let pointer_width = env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap(); + if pointer_width == "64" { build.define("BACKTRACE_ELF_SIZE", "64"); } else { build.define("BACKTRACE_ELF_SIZE", "32"); @@ -126,7 +122,8 @@ fn build_libbacktrace(target: &str) -> Result<(), ()> { if !target.contains("apple-ios") && !target.contains("solaris") && !target.contains("redox") && - !target.contains("android") { + !target.contains("android") && + !target.contains("haiku") { build.define("HAVE_DL_ITERATE_PHDR", "1"); } build.define("_GNU_SOURCE", "1"); diff --git a/ctr-std/src/collections/hash/map.rs b/ctr-std/src/collections/hash/map.rs index 9c77acb..91912e5 100644 --- a/ctr-std/src/collections/hash/map.rs +++ b/ctr-std/src/collections/hash/map.rs @@ -11,7 +11,7 @@ use self::Entry::*; use self::VacantEntryState::*; -use alloc::CollectionAllocErr; +use collections::CollectionAllocErr; use cell::Cell; use borrow::Borrow; use cmp::max; @@ -276,17 +276,31 @@ const DISPLACEMENT_THRESHOLD: usize = 128; /// ``` /// use std::collections::HashMap; /// -/// // type inference lets us omit an explicit type signature (which -/// // would be `HashMap<&str, &str>` in this example). +/// // Type inference lets us omit an explicit type signature (which +/// // would be `HashMap` in this example). /// let mut book_reviews = HashMap::new(); /// -/// // review some books. -/// book_reviews.insert("Adventures of Huckleberry Finn", "My favorite book."); -/// book_reviews.insert("Grimms' Fairy Tales", "Masterpiece."); -/// book_reviews.insert("Pride and Prejudice", "Very enjoyable."); -/// book_reviews.insert("The Adventures of Sherlock Holmes", "Eye lyked it alot."); +/// // Review some books. +/// book_reviews.insert( +/// "Adventures of Huckleberry Finn".to_string(), +/// "My favorite book.".to_string(), +/// ); +/// book_reviews.insert( +/// "Grimms' Fairy Tales".to_string(), +/// "Masterpiece.".to_string(), +/// ); +/// book_reviews.insert( +/// "Pride and Prejudice".to_string(), +/// "Very enjoyable.".to_string(), +/// ); +/// book_reviews.insert( +/// "The Adventures of Sherlock Holmes".to_string(), +/// "Eye lyked it alot.".to_string(), +/// ); /// -/// // check for a specific one. +/// // Check for a specific one. +/// // When collections store owned values (String), they can still be +/// // queried using references (&str). /// if !book_reviews.contains_key("Les Misérables") { /// println!("We've got {} reviews, but Les Misérables ain't one.", /// book_reviews.len()); @@ -295,16 +309,16 @@ const DISPLACEMENT_THRESHOLD: usize = 128; /// // oops, this review has a lot of spelling mistakes, let's delete it. /// book_reviews.remove("The Adventures of Sherlock Holmes"); /// -/// // look up the values associated with some keys. +/// // Look up the values associated with some keys. /// let to_find = ["Pride and Prejudice", "Alice's Adventure in Wonderland"]; -/// for book in &to_find { +/// for &book in &to_find { /// match book_reviews.get(book) { /// Some(review) => println!("{}: {}", book, review), /// None => println!("{} is unreviewed.", book) /// } /// } /// -/// // iterate over everything. +/// // Iterate over everything. /// for (book, review) in &book_reviews { /// println!("{}: \"{}\"", book, review); /// } diff --git a/ctr-std/src/collections/hash/set.rs b/ctr-std/src/collections/hash/set.rs index 855563a..5ac3e8f 100644 --- a/ctr-std/src/collections/hash/set.rs +++ b/ctr-std/src/collections/hash/set.rs @@ -49,14 +49,14 @@ use super::map::{self, HashMap, Keys, RandomState}; /// ``` /// use std::collections::HashSet; /// // Type inference lets us omit an explicit type signature (which -/// // would be `HashSet<&str>` in this example). +/// // would be `HashSet` in this example). /// let mut books = HashSet::new(); /// /// // Add some books. -/// books.insert("A Dance With Dragons"); -/// books.insert("To Kill a Mockingbird"); -/// books.insert("The Odyssey"); -/// books.insert("The Great Gatsby"); +/// books.insert("A Dance With Dragons".to_string()); +/// books.insert("To Kill a Mockingbird".to_string()); +/// books.insert("The Odyssey".to_string()); +/// books.insert("The Great Gatsby".to_string()); /// /// // Check for a specific one. /// if !books.contains("The Winds of Winter") { @@ -80,17 +80,17 @@ use super::map::{self, HashMap, Keys, RandomState}; /// ``` /// use std::collections::HashSet; /// #[derive(Hash, Eq, PartialEq, Debug)] -/// struct Viking<'a> { -/// name: &'a str, +/// struct Viking { +/// name: String, /// power: usize, /// } /// /// let mut vikings = HashSet::new(); /// -/// vikings.insert(Viking { name: "Einar", power: 9 }); -/// vikings.insert(Viking { name: "Einar", power: 9 }); -/// vikings.insert(Viking { name: "Olaf", power: 4 }); -/// vikings.insert(Viking { name: "Harald", power: 8 }); +/// vikings.insert(Viking { name: "Einar".to_string(), power: 9 }); +/// vikings.insert(Viking { name: "Einar".to_string(), power: 9 }); +/// vikings.insert(Viking { name: "Olaf".to_string(), power: 4 }); +/// vikings.insert(Viking { name: "Harald".to_string(), power: 8 }); /// /// // Use derived implementation to print the vikings. /// for x in &vikings { @@ -104,7 +104,7 @@ use super::map::{self, HashMap, Keys, RandomState}; /// use std::collections::HashSet; /// /// fn main() { -/// let viking_names: HashSet<&str> = +/// let viking_names: HashSet<&'static str> = /// [ "Einar", "Olaf", "Harald" ].iter().cloned().collect(); /// // use the values stored in the set /// } diff --git a/ctr-std/src/collections/hash/table.rs b/ctr-std/src/collections/hash/table.rs index d997fb2..2b31918 100644 --- a/ctr-std/src/collections/hash/table.rs +++ b/ctr-std/src/collections/hash/table.rs @@ -8,7 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use alloc::{Global, Alloc, Layout, LayoutErr, CollectionAllocErr, oom}; +use alloc::{Global, Alloc, Layout, LayoutErr, handle_alloc_error}; +use collections::CollectionAllocErr; use hash::{BuildHasher, Hash, Hasher}; use marker; use mem::{size_of, needs_drop}; @@ -699,7 +700,7 @@ impl RawTable { // point into it. let (layout, _) = calculate_layout::(capacity)?; let buffer = Global.alloc(layout).map_err(|e| match fallibility { - Infallible => oom(layout), + Infallible => handle_alloc_error(layout), Fallible => e, })?; @@ -1124,7 +1125,7 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable { let (layout, _) = calculate_layout::(self.capacity()) .unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() }); unsafe { - Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).as_opaque(), layout); + Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).cast(), layout); // Remember how everything was allocated out of one buffer // during initialization? We only need one call to free here. } diff --git a/ctr-std/src/collections/mod.rs b/ctr-std/src/collections/mod.rs index d8e79b9..8d2c82b 100644 --- a/ctr-std/src/collections/mod.rs +++ b/ctr-std/src/collections/mod.rs @@ -424,13 +424,13 @@ #[doc(hidden)] pub use ops::Bound; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc_crate::{BinaryHeap, BTreeMap, BTreeSet}; +pub use alloc_crate::collections::{BinaryHeap, BTreeMap, BTreeSet}; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc_crate::{LinkedList, VecDeque}; +pub use alloc_crate::collections::{LinkedList, VecDeque}; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc_crate::{binary_heap, btree_map, btree_set}; +pub use alloc_crate::collections::{binary_heap, btree_map, btree_set}; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc_crate::{linked_list, vec_deque}; +pub use alloc_crate::collections::{linked_list, vec_deque}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::hash_map::HashMap; @@ -438,7 +438,7 @@ pub use self::hash_map::HashMap; pub use self::hash_set::HashSet; #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] -pub use heap::CollectionAllocErr; +pub use alloc_crate::collections::CollectionAllocErr; mod hash; diff --git a/ctr-std/src/env.rs b/ctr-std/src/env.rs index 91e417c..9066c0b 100644 --- a/ctr-std/src/env.rs +++ b/ctr-std/src/env.rs @@ -512,18 +512,20 @@ impl Error for JoinPathsError { /// /// # Unix /// -/// Returns the value of the 'HOME' environment variable if it is set -/// and not equal to the empty string. Otherwise, it tries to determine the -/// home directory by invoking the `getpwuid_r` function on the UID of the -/// current user. +/// - Returns the value of the 'HOME' environment variable if it is set +/// (including to an empty string). +/// - Otherwise, it tries to determine the home directory by invoking the `getpwuid_r` function +/// using the UID of the current user. An empty home directory field returned from the +/// `getpwuid_r` function is considered to be a valid value. +/// - Returns `None` if the current user has no entry in the /etc/passwd file. /// /// # Windows /// -/// Returns the value of the 'HOME' environment variable if it is -/// set and not equal to the empty string. Otherwise, returns the value of the -/// 'USERPROFILE' environment variable if it is set and not equal to the empty -/// string. If both do not exist, [`GetUserProfileDirectory`][msdn] is used to -/// return the appropriate path. +/// - Returns the value of the 'HOME' environment variable if it is set +/// (including to an empty string). +/// - Otherwise, returns the value of the 'USERPROFILE' environment variable if it is set +/// (including to an empty string). +/// - If both do not exist, [`GetUserProfileDirectory`][msdn] is used to return the path. /// /// [msdn]: https://msdn.microsoft.com/en-us/library/windows/desktop/bb762280(v=vs.85).aspx /// @@ -533,10 +535,13 @@ impl Error for JoinPathsError { /// use std::env; /// /// match env::home_dir() { -/// Some(path) => println!("{}", path.display()), +/// Some(path) => println!("Your home directory, probably: {}", path.display()), /// None => println!("Impossible to get your home dir!"), /// } /// ``` +#[rustc_deprecated(since = "1.29.0", + reason = "This function's behavior is unexpected and probably not what you want. \ + Consider using the home_dir function from https://crates.io/crates/dirs instead.")] #[stable(feature = "env", since = "1.0.0")] pub fn home_dir() -> Option { os_imp::home_dir() diff --git a/ctr-std/src/error.rs b/ctr-std/src/error.rs index 817eea5..2953469 100644 --- a/ctr-std/src/error.rs +++ b/ctr-std/src/error.rs @@ -23,13 +23,13 @@ // coherence challenge (e.g., specialization, neg impls, etc) we can // reconsider what crate these items belong in. +use alloc::{AllocErr, LayoutErr, CannotReallocInPlace}; use any::TypeId; use borrow::Cow; use cell; use char; use core::array; use fmt::{self, Debug, Display}; -use heap::{AllocErr, LayoutErr, CannotReallocInPlace}; use mem::transmute; use num; use str; @@ -49,6 +49,7 @@ use string; /// /// [`Result`]: ../result/enum.Result.html /// [`Display`]: ../fmt/trait.Display.html +/// [`Debug`]: ../fmt/trait.Debug.html /// [`cause`]: trait.Error.html#method.cause #[stable(feature = "rust1", since = "1.0.0")] pub trait Error: Debug + Display { @@ -137,7 +138,7 @@ pub trait Error: Debug + Display { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - fn cause(&self) -> Option<&Error> { None } + fn cause(&self) -> Option<&dyn Error> { None } /// Get the `TypeId` of `self` #[doc(hidden)] @@ -150,22 +151,22 @@ pub trait Error: Debug + Display { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, E: Error + 'a> From for Box { - fn from(err: E) -> Box { +impl<'a, E: Error + 'a> From for Box { + fn from(err: E) -> Box { Box::new(err) } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, E: Error + Send + Sync + 'a> From for Box { - fn from(err: E) -> Box { +impl<'a, E: Error + Send + Sync + 'a> From for Box { + fn from(err: E) -> Box { Box::new(err) } } #[stable(feature = "rust1", since = "1.0.0")] -impl From for Box { - fn from(err: String) -> Box { +impl From for Box { + fn from(err: String) -> Box { #[derive(Debug)] struct StringError(String); @@ -184,38 +185,38 @@ impl From for Box { } #[stable(feature = "string_box_error", since = "1.6.0")] -impl From for Box { - fn from(str_err: String) -> Box { - let err1: Box = From::from(str_err); - let err2: Box = err1; +impl From for Box { + fn from(str_err: String) -> Box { + let err1: Box = From::from(str_err); + let err2: Box = err1; err2 } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, 'b> From<&'b str> for Box { - fn from(err: &'b str) -> Box { +impl<'a, 'b> From<&'b str> for Box { + fn from(err: &'b str) -> Box { From::from(String::from(err)) } } #[stable(feature = "string_box_error", since = "1.6.0")] -impl<'a> From<&'a str> for Box { - fn from(err: &'a str) -> Box { +impl<'a> From<&'a str> for Box { + fn from(err: &'a str) -> Box { From::from(String::from(err)) } } #[stable(feature = "cow_box_error", since = "1.22.0")] -impl<'a, 'b> From> for Box { - fn from(err: Cow<'b, str>) -> Box { +impl<'a, 'b> From> for Box { + fn from(err: Cow<'b, str>) -> Box { From::from(String::from(err)) } } #[stable(feature = "cow_box_error", since = "1.22.0")] -impl<'a> From> for Box { - fn from(err: Cow<'a, str>) -> Box { +impl<'a> From> for Box { + fn from(err: Cow<'a, str>) -> Box { From::from(String::from(err)) } } @@ -326,7 +327,7 @@ impl Error for Box { Error::description(&**self) } - fn cause(&self) -> Option<&Error> { + fn cause(&self) -> Option<&dyn Error> { Error::cause(&**self) } } @@ -367,7 +368,7 @@ impl Error for char::ParseCharError { } // copied from any.rs -impl Error + 'static { +impl dyn Error + 'static { /// Returns true if the boxed type is the same as `T` #[stable(feature = "error_downcast", since = "1.3.0")] #[inline] @@ -389,7 +390,7 @@ impl Error + 'static { pub fn downcast_ref(&self) -> Option<&T> { if self.is::() { unsafe { - Some(&*(self as *const Error as *const T)) + Some(&*(self as *const dyn Error as *const T)) } } else { None @@ -403,7 +404,7 @@ impl Error + 'static { pub fn downcast_mut(&mut self) -> Option<&mut T> { if self.is::() { unsafe { - Some(&mut *(self as *mut Error as *mut T)) + Some(&mut *(self as *mut dyn Error as *mut T)) } } else { None @@ -411,60 +412,60 @@ impl Error + 'static { } } -impl Error + 'static + Send { +impl dyn Error + 'static + Send { /// Forwards to the method defined on the type `Any`. #[stable(feature = "error_downcast", since = "1.3.0")] #[inline] pub fn is(&self) -> bool { - ::is::(self) + ::is::(self) } /// Forwards to the method defined on the type `Any`. #[stable(feature = "error_downcast", since = "1.3.0")] #[inline] pub fn downcast_ref(&self) -> Option<&T> { - ::downcast_ref::(self) + ::downcast_ref::(self) } /// Forwards to the method defined on the type `Any`. #[stable(feature = "error_downcast", since = "1.3.0")] #[inline] pub fn downcast_mut(&mut self) -> Option<&mut T> { - ::downcast_mut::(self) + ::downcast_mut::(self) } } -impl Error + 'static + Send + Sync { +impl dyn Error + 'static + Send + Sync { /// Forwards to the method defined on the type `Any`. #[stable(feature = "error_downcast", since = "1.3.0")] #[inline] pub fn is(&self) -> bool { - ::is::(self) + ::is::(self) } /// Forwards to the method defined on the type `Any`. #[stable(feature = "error_downcast", since = "1.3.0")] #[inline] pub fn downcast_ref(&self) -> Option<&T> { - ::downcast_ref::(self) + ::downcast_ref::(self) } /// Forwards to the method defined on the type `Any`. #[stable(feature = "error_downcast", since = "1.3.0")] #[inline] pub fn downcast_mut(&mut self) -> Option<&mut T> { - ::downcast_mut::(self) + ::downcast_mut::(self) } } -impl Error { +impl dyn Error { #[inline] #[stable(feature = "error_downcast", since = "1.3.0")] /// Attempt to downcast the box to a concrete type. - pub fn downcast(self: Box) -> Result, Box> { + pub fn downcast(self: Box) -> Result, Box> { if self.is::() { unsafe { - let raw: *mut Error = Box::into_raw(self); + let raw: *mut dyn Error = Box::into_raw(self); Ok(Box::from_raw(raw as *mut T)) } } else { @@ -473,30 +474,30 @@ impl Error { } } -impl Error + Send { +impl dyn Error + Send { #[inline] #[stable(feature = "error_downcast", since = "1.3.0")] /// Attempt to downcast the box to a concrete type. pub fn downcast(self: Box) - -> Result, Box> { - let err: Box = self; - ::downcast(err).map_err(|s| unsafe { + -> Result, Box> { + let err: Box = self; + ::downcast(err).map_err(|s| unsafe { // reapply the Send marker - transmute::, Box>(s) + transmute::, Box>(s) }) } } -impl Error + Send + Sync { +impl dyn Error + Send + Sync { #[inline] #[stable(feature = "error_downcast", since = "1.3.0")] /// Attempt to downcast the box to a concrete type. pub fn downcast(self: Box) -> Result, Box> { - let err: Box = self; - ::downcast(err).map_err(|s| unsafe { + let err: Box = self; + ::downcast(err).map_err(|s| unsafe { // reapply the Send+Sync marker - transmute::, Box>(s) + transmute::, Box>(s) }) } } @@ -532,13 +533,13 @@ mod tests { #[test] fn downcasting() { let mut a = A; - let a = &mut a as &mut (Error + 'static); + let a = &mut a as &mut (dyn Error + 'static); assert_eq!(a.downcast_ref::(), Some(&A)); assert_eq!(a.downcast_ref::(), None); assert_eq!(a.downcast_mut::(), Some(&mut A)); assert_eq!(a.downcast_mut::(), None); - let a: Box = Box::new(A); + let a: Box = Box::new(A); match a.downcast::() { Ok(..) => panic!("expected error"), Err(e) => assert_eq!(*e.downcast::().unwrap(), A), diff --git a/ctr-std/src/f32.rs b/ctr-std/src/f32.rs index ae30321..8e8340b 100644 --- a/ctr-std/src/f32.rs +++ b/ctr-std/src/f32.rs @@ -254,7 +254,14 @@ impl f32 { /// Calculates the Euclidean modulo (self mod rhs), which is never negative. /// - /// In particular, the result `n` satisfies `0 <= n < rhs.abs()`. + /// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in + /// most cases. However, due to a floating point round-off error it can + /// result in `r == rhs.abs()`, violating the mathematical definition, if + /// `self` is much smaller than `rhs.abs()` in magnitude and `self < 0.0`. + /// This result is not an element of the function's codomain, but it is the + /// closest floating point number in the real numbers and thus fulfills the + /// property `self == self.div_euc(rhs) * rhs + self.mod_euc(rhs)` + /// approximatively. /// /// # Examples /// @@ -266,6 +273,8 @@ impl f32 { /// assert_eq!((-a).mod_euc(b), 1.0); /// assert_eq!(a.mod_euc(-b), 3.0); /// assert_eq!((-a).mod_euc(-b), 1.0); + /// // limitation due to round-off error + /// assert!((-std::f32::EPSILON).mod_euc(3.0) != 0.0); /// ``` #[inline] #[unstable(feature = "euclidean_division", issue = "49048")] diff --git a/ctr-std/src/f64.rs b/ctr-std/src/f64.rs index 7950d43..6880294 100644 --- a/ctr-std/src/f64.rs +++ b/ctr-std/src/f64.rs @@ -230,7 +230,14 @@ impl f64 { /// Calculates the Euclidean modulo (self mod rhs), which is never negative. /// - /// In particular, the result `n` satisfies `0 <= n < rhs.abs()`. + /// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in + /// most cases. However, due to a floating point round-off error it can + /// result in `r == rhs.abs()`, violating the mathematical definition, if + /// `self` is much smaller than `rhs.abs()` in magnitude and `self < 0.0`. + /// This result is not an element of the function's codomain, but it is the + /// closest floating point number in the real numbers and thus fulfills the + /// property `self == self.div_euc(rhs) * rhs + self.mod_euc(rhs)` + /// approximatively. /// /// # Examples /// @@ -242,6 +249,8 @@ impl f64 { /// assert_eq!((-a).mod_euc(b), 1.0); /// assert_eq!(a.mod_euc(-b), 3.0); /// assert_eq!((-a).mod_euc(-b), 1.0); + /// // limitation due to round-off error + /// assert!((-std::f64::EPSILON).mod_euc(3.0) != 0.0); /// ``` #[inline] #[unstable(feature = "euclidean_division", issue = "49048")] diff --git a/ctr-std/src/ffi/c_str.rs b/ctr-std/src/ffi/c_str.rs index 52372df..06edd29 100644 --- a/ctr-std/src/ffi/c_str.rs +++ b/ctr-std/src/ffi/c_str.rs @@ -692,6 +692,12 @@ impl fmt::Debug for CString { #[stable(feature = "cstring_into", since = "1.7.0")] impl From for Vec { + /// Converts a [`CString`] into a [`Vec`]``. + /// + /// The conversion consumes the [`CString`], and removes the terminating NUL byte. + /// + /// [`Vec`]: ../vec/struct.Vec.html + /// [`CString`]: ../ffi/struct.CString.html #[inline] fn from(s: CString) -> Vec { s.into_bytes() @@ -750,14 +756,30 @@ impl<'a> From<&'a CStr> for Box { #[stable(feature = "c_string_from_box", since = "1.18.0")] impl From> for CString { + /// Converts a [`Box`]`` into a [`CString`] without copying or allocating. + /// + /// [`Box`]: ../boxed/struct.Box.html + /// [`CString`]: ../ffi/struct.CString.html #[inline] fn from(s: Box) -> CString { s.into_c_string() } } +#[stable(feature = "more_box_slice_clone", since = "1.29.0")] +impl Clone for Box { + #[inline] + fn clone(&self) -> Self { + (**self).into() + } +} + #[stable(feature = "box_from_c_string", since = "1.20.0")] impl From for Box { + /// Converts a [`CString`] into a [`Box`]`` without copying or allocating. + /// + /// [`CString`]: ../ffi/struct.CString.html + /// [`Box`]: ../boxed/struct.Box.html #[inline] fn from(s: CString) -> Box { s.into_boxed_c_str() @@ -790,6 +812,10 @@ impl<'a> From<&'a CString> for Cow<'a, CStr> { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Arc { + /// Converts a [`CString`] into a [`Arc`]`` without copying or allocating. + /// + /// [`CString`]: ../ffi/struct.CString.html + /// [`Arc`]: ../sync/struct.Arc.html #[inline] fn from(s: CString) -> Arc { let arc: Arc<[u8]> = Arc::from(s.into_inner()); @@ -808,6 +834,10 @@ impl<'a> From<&'a CStr> for Arc { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Rc { + /// Converts a [`CString`] into a [`Rc`]`` without copying or allocating. + /// + /// [`CString`]: ../ffi/struct.CString.html + /// [`Rc`]: ../rc/struct.Rc.html #[inline] fn from(s: CString) -> Rc { let rc: Rc<[u8]> = Rc::from(s.into_inner()); @@ -881,6 +911,10 @@ impl fmt::Display for NulError { #[stable(feature = "rust1", since = "1.0.0")] impl From for io::Error { + /// Converts a [`NulError`] into a [`io::Error`]. + /// + /// [`NulError`]: ../ffi/struct.NulError.html + /// [`io::Error`]: ../io/struct.Error.html fn from(_: NulError) -> io::Error { io::Error::new(io::ErrorKind::InvalidInput, "data provided contains a nul byte") @@ -933,7 +967,7 @@ impl Error for IntoStringError { "C string contained non-utf8 bytes" } - fn cause(&self) -> Option<&Error> { + fn cause(&self) -> Option<&dyn Error> { Some(&self.error) } } @@ -1234,9 +1268,9 @@ impl CStr { /// If the contents of the `CStr` are valid UTF-8 data, this /// function will return a [`Cow`]`::`[`Borrowed`]`(`[`&str`]`)` /// with the the corresponding [`&str`] slice. Otherwise, it will - /// replace any invalid UTF-8 sequences with `U+FFFD REPLACEMENT - /// CHARACTER` and return a [`Cow`]`::`[`Owned`]`(`[`String`]`)` - /// with the result. + /// replace any invalid UTF-8 sequences with + /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD] and return a + /// [`Cow`]`::`[`Owned`]`(`[`String`]`)` with the result. /// /// > **Note**: This method is currently implemented to check for validity /// > after a constant-time cast, but it is planned to alter its definition @@ -1248,6 +1282,7 @@ impl CStr { /// [`Owned`]: ../borrow/enum.Cow.html#variant.Owned /// [`str`]: ../primitive.str.html /// [`String`]: ../string/struct.String.html + /// [U+FFFD]: ../char/constant.REPLACEMENT_CHARACTER.html /// /// # Examples /// diff --git a/ctr-std/src/ffi/os_str.rs b/ctr-std/src/ffi/os_str.rs index 0a31480..6bcd62d 100644 --- a/ctr-std/src/ffi/os_str.rs +++ b/ctr-std/src/ffi/os_str.rs @@ -348,6 +348,12 @@ impl OsString { #[stable(feature = "rust1", since = "1.0.0")] impl From for OsString { + /// Converts a [`String`] into a [`OsString`]. + /// + /// The conversion copies the data, and includes an allocation on the heap. + /// + /// [`String`]: ../string/struct.String.html + /// [`OsString`]: struct.OsString.html fn from(s: String) -> OsString { OsString { inner: Buf::from_string(s) } } @@ -417,6 +423,20 @@ impl PartialEq for str { } } +#[stable(feature = "os_str_str_ref_eq", since = "1.28.0")] +impl<'a> PartialEq<&'a str> for OsString { + fn eq(&self, other: &&'a str) -> bool { + **self == **other + } +} + +#[stable(feature = "os_str_str_ref_eq", since = "1.28.0")] +impl<'a> PartialEq for &'a str { + fn eq(&self, other: &OsString) -> bool { + **other == **self + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Eq for OsString {} @@ -500,10 +520,12 @@ impl OsStr { /// Converts an `OsStr` to a [`Cow`]`<`[`str`]`>`. /// - /// Any non-Unicode sequences are replaced with U+FFFD REPLACEMENT CHARACTER. + /// Any non-Unicode sequences are replaced with + /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD]. /// /// [`Cow`]: ../../std/borrow/enum.Cow.html /// [`str`]: ../../std/primitive.str.html + /// [U+FFFD]: ../../std/char/constant.REPLACEMENT_CHARACTER.html /// /// # Examples /// @@ -616,6 +638,10 @@ impl<'a> From<&'a OsStr> for Box { #[stable(feature = "os_string_from_box", since = "1.18.0")] impl From> for OsString { + /// Converts a `Box` into a `OsString` without copying or allocating. + /// + /// [`Box`]: ../boxed/struct.Box.html + /// [`OsString`]: ../ffi/struct.OsString.html fn from(boxed: Box) -> OsString { boxed.into_os_string() } @@ -623,13 +649,29 @@ impl From> for OsString { #[stable(feature = "box_from_os_string", since = "1.20.0")] impl From for Box { + /// Converts a [`OsString`] into a [`Box`]`` without copying or allocating. + /// + /// [`Box`]: ../boxed/struct.Box.html + /// [`OsString`]: ../ffi/struct.OsString.html fn from(s: OsString) -> Box { s.into_boxed_os_str() } } +#[stable(feature = "more_box_slice_clone", since = "1.29.0")] +impl Clone for Box { + #[inline] + fn clone(&self) -> Self { + self.to_os_string().into_boxed_os_str() + } +} + #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Arc { + /// Converts a [`OsString`] into a [`Arc`]`` without copying or allocating. + /// + /// [`Arc`]: ../sync/struct.Arc.html + /// [`OsString`]: ../ffi/struct.OsString.html #[inline] fn from(s: OsString) -> Arc { let arc = s.inner.into_arc(); @@ -648,6 +690,10 @@ impl<'a> From<&'a OsStr> for Arc { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Rc { + /// Converts a [`OsString`] into a [`Rc`]`` without copying or allocating. + /// + /// [`Rc`]: ../rc/struct.Rc.html + /// [`OsString`]: ../ffi/struct.OsString.html #[inline] fn from(s: OsString) -> Rc { let rc = s.inner.into_rc(); diff --git a/ctr-std/src/fs.rs b/ctr-std/src/fs.rs index 987687e..7632fbc 100644 --- a/ctr-std/src/fs.rs +++ b/ctr-std/src/fs.rs @@ -356,9 +356,9 @@ impl File { /// use std::fs::File; /// /// fn main() -> std::io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// # Ok(()) - /// # } + /// let mut f = File::open("foo.txt")?; + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn open>(path: P) -> io::Result { diff --git a/ctr-std/src/future.rs b/ctr-std/src/future.rs new file mode 100644 index 0000000..12ea1ea --- /dev/null +++ b/ctr-std/src/future.rs @@ -0,0 +1,116 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Asynchronous values. + +use core::cell::Cell; +use core::marker::Unpin; +use core::mem::PinMut; +use core::option::Option; +use core::ptr::NonNull; +use core::task::{self, Poll}; +use core::ops::{Drop, Generator, GeneratorState}; + +#[doc(inline)] +pub use core::future::*; + +/// Wrap a future in a generator. +/// +/// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give +/// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`). +#[unstable(feature = "gen_future", issue = "50547")] +pub fn from_generator>(x: T) -> impl Future { + GenFuture(x) +} + +/// A wrapper around generators used to implement `Future` for `async`/`await` code. +#[unstable(feature = "gen_future", issue = "50547")] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] +struct GenFuture>(T); + +// We rely on the fact that async/await futures are immovable in order to create +// self-referential borrows in the underlying generator. +impl> !Unpin for GenFuture {} + +#[unstable(feature = "gen_future", issue = "50547")] +impl> Future for GenFuture { + type Output = T::Return; + fn poll(self: PinMut, cx: &mut task::Context) -> Poll { + set_task_cx(cx, || match unsafe { PinMut::get_mut_unchecked(self).0.resume() } { + GeneratorState::Yielded(()) => Poll::Pending, + GeneratorState::Complete(x) => Poll::Ready(x), + }) + } +} + +thread_local! { + static TLS_CX: Cell>>> = Cell::new(None); +} + +struct SetOnDrop(Option>>); + +impl Drop for SetOnDrop { + fn drop(&mut self) { + TLS_CX.with(|tls_cx| { + tls_cx.set(self.0.take()); + }); + } +} + +#[unstable(feature = "gen_future", issue = "50547")] +/// Sets the thread-local task context used by async/await futures. +pub fn set_task_cx(cx: &mut task::Context, f: F) -> R +where + F: FnOnce() -> R +{ + let old_cx = TLS_CX.with(|tls_cx| { + tls_cx.replace(NonNull::new( + cx + as *mut task::Context + as *mut () + as *mut task::Context<'static> + )) + }); + let _reset_cx = SetOnDrop(old_cx); + f() +} + +#[unstable(feature = "gen_future", issue = "50547")] +/// Retrieves the thread-local task context used by async/await futures. +/// +/// This function acquires exclusive access to the task context. +/// +/// Panics if no task has been set or if the task context has already been +/// retrived by a surrounding call to get_task_cx. +pub fn get_task_cx(f: F) -> R +where + F: FnOnce(&mut task::Context) -> R +{ + let cx_ptr = TLS_CX.with(|tls_cx| { + // Clear the entry so that nested `with_get_cx` calls + // will fail or set their own value. + tls_cx.replace(None) + }); + let _reset_cx = SetOnDrop(cx_ptr); + + let mut cx_ptr = cx_ptr.expect( + "TLS task::Context not set. This is a rustc bug. \ + Please file an issue on https://github.com/rust-lang/rust."); + unsafe { f(cx_ptr.as_mut()) } +} + +#[unstable(feature = "gen_future", issue = "50547")] +/// Polls a future in the current thread-local task context. +pub fn poll_in_task_cx(f: PinMut) -> Poll +where + F: Future +{ + get_task_cx(|cx| f.poll(cx)) +} diff --git a/ctr-std/src/io/buffered.rs b/ctr-std/src/io/buffered.rs index ee297d3..03c97de 100644 --- a/ctr-std/src/io/buffered.rs +++ b/ctr-std/src/io/buffered.rs @@ -61,7 +61,8 @@ pub struct BufReader { } impl BufReader { - /// Creates a new `BufReader` with a default buffer capacity. + /// Creates a new `BufReader` with a default buffer capacity. The default is currently 8 KB, + /// but may change in the future. /// /// # Examples /// @@ -153,33 +154,6 @@ impl BufReader { #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self) -> &mut R { &mut self.inner } - /// Returns `true` if there are no bytes in the internal buffer. - /// - /// # Examples - // - /// ```no_run - /// # #![feature(bufreader_is_empty)] - /// use std::io::BufReader; - /// use std::io::BufRead; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let f1 = File::open("log.txt")?; - /// let mut reader = BufReader::new(f1); - /// assert!(reader.is_empty()); - /// - /// if reader.fill_buf()?.len() > 0 { - /// assert!(!reader.is_empty()); - /// } - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "bufreader_is_empty", issue = "45323", reason = "recently added")] - #[rustc_deprecated(since = "1.26.0", reason = "use .buffer().is_empty() instead")] - pub fn is_empty(&self) -> bool { - self.buffer().is_empty() - } - /// Returns a reference to the internally buffered data. /// /// Unlike `fill_buf`, this will not attempt to fill the buffer if it is empty. @@ -454,7 +428,8 @@ pub struct BufWriter { pub struct IntoInnerError(W, Error); impl BufWriter { - /// Creates a new `BufWriter` with a default buffer capacity. + /// Creates a new `BufWriter` with a default buffer capacity. The default is currently 8 KB, + /// but may change in the future. /// /// # Examples /// @@ -738,7 +713,7 @@ impl fmt::Display for IntoInnerError { /// reducing the number of actual writes to the file. /// /// ```no_run -/// use std::fs::File; +/// use std::fs::{self, File}; /// use std::io::prelude::*; /// use std::io::LineWriter; /// @@ -752,17 +727,30 @@ impl fmt::Display for IntoInnerError { /// let file = File::create("poem.txt")?; /// let mut file = LineWriter::new(file); /// -/// for &byte in road_not_taken.iter() { -/// file.write(&[byte]).unwrap(); -/// } +/// file.write_all(b"I shall be telling this with a sigh")?; /// -/// // let's check we did the right thing. -/// let mut file = File::open("poem.txt")?; -/// let mut contents = String::new(); +/// // No bytes are written until a newline is encountered (or +/// // the internal buffer is filled). +/// assert_eq!(fs::read_to_string("poem.txt")?, ""); +/// file.write_all(b"\n")?; +/// assert_eq!( +/// fs::read_to_string("poem.txt")?, +/// "I shall be telling this with a sigh\n", +/// ); /// -/// file.read_to_string(&mut contents)?; +/// // Write the rest of the poem. +/// file.write_all(b"Somewhere ages and ages hence: +/// Two roads diverged in a wood, and I - +/// I took the one less traveled by, +/// And that has made all the difference.")?; /// -/// assert_eq!(contents.as_bytes(), &road_not_taken[..]); +/// // The last line of the poem doesn't end in a newline, so +/// // we have to flush or drop the `LineWriter` to finish +/// // writing. +/// file.flush()?; +/// +/// // Confirm the whole poem was written. +/// assert_eq!(fs::read("poem.txt")?, &road_not_taken[..]); /// Ok(()) /// } /// ``` @@ -862,7 +850,7 @@ impl LineWriter { /// /// The internal buffer is written out before returning the writer. /// - // # Errors + /// # Errors /// /// An `Err` will be returned if an error occurs while flushing the buffer. /// @@ -1250,25 +1238,6 @@ mod tests { assert_eq!(reader.read(&mut buf).unwrap(), 0); } - #[test] - #[allow(deprecated)] - fn read_char_buffered() { - let buf = [195, 159]; - let reader = BufReader::with_capacity(1, &buf[..]); - assert_eq!(reader.chars().next().unwrap().unwrap(), 'ß'); - } - - #[test] - #[allow(deprecated)] - fn test_chars() { - let buf = [195, 159, b'a']; - let reader = BufReader::with_capacity(1, &buf[..]); - let mut it = reader.chars(); - assert_eq!(it.next().unwrap().unwrap(), 'ß'); - assert_eq!(it.next().unwrap().unwrap(), 'a'); - assert!(it.next().is_none()); - } - #[test] #[should_panic] fn dont_panic_in_drop_on_panicked_flush() { diff --git a/ctr-std/src/io/cursor.rs b/ctr-std/src/io/cursor.rs index 8ac5257..14f2015 100644 --- a/ctr-std/src/io/cursor.rs +++ b/ctr-std/src/io/cursor.rs @@ -10,15 +10,17 @@ use io::prelude::*; +use core::convert::TryInto; use cmp; use io::{self, Initializer, SeekFrom, Error, ErrorKind}; -/// A `Cursor` wraps another type and provides it with a +/// A `Cursor` wraps an in-memory buffer and provides it with a /// [`Seek`] implementation. /// -/// `Cursor`s are typically used with in-memory buffers to allow them to -/// implement [`Read`] and/or [`Write`], allowing these buffers to be used -/// anywhere you might use a reader or writer that does actual I/O. +/// `Cursor`s are used with in-memory buffers, anything implementing +/// `AsRef<[u8]>`, to allow them to implement [`Read`] and/or [`Write`], +/// allowing these buffers to be used anywhere you might use a reader or writer +/// that does actual I/O. /// /// The standard library implements some I/O traits on various types which /// are commonly used as a buffer, like `Cursor<`[`Vec`]`>` and @@ -86,11 +88,11 @@ pub struct Cursor { } impl Cursor { - /// Creates a new cursor wrapping the provided underlying I/O object. + /// Creates a new cursor wrapping the provided underlying in-memory buffer. /// - /// Cursor initial position is `0` even if underlying object (e. - /// g. `Vec`) is not empty. So writing to cursor starts with - /// overwriting `Vec` content, not with appending to it. + /// Cursor initial position is `0` even if underlying buffer (e.g. `Vec`) + /// is not empty. So writing to cursor starts with overwriting `Vec` + /// content, not with appending to it. /// /// # Examples /// @@ -259,26 +261,9 @@ fn slice_write(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> io::Result Result { - if n <= (::max_value() as u64) { - Ok(n as usize) - } else { - Err(()) - } -} - -#[cfg(any(target_pointer_width = "64"))] -fn try_into(n: u64) -> Result { - Ok(n as usize) -} - // Resizing write implementation fn vec_write(pos_mut: &mut u64, vec: &mut Vec, buf: &[u8]) -> io::Result { - let pos: usize = try_into(*pos_mut).map_err(|_| { + let pos: usize = (*pos_mut).try_into().map_err(|_| { Error::new(ErrorKind::InvalidInput, "cursor position exceeds maximum possible vector length") })?; @@ -565,26 +550,6 @@ mod tests { assert_eq!(reader.read(&mut buf).unwrap(), 0); } - #[test] - #[allow(deprecated)] - fn test_read_char() { - let b = &b"Vi\xE1\xBB\x87t"[..]; - let mut c = Cursor::new(b).chars(); - assert_eq!(c.next().unwrap().unwrap(), 'V'); - assert_eq!(c.next().unwrap().unwrap(), 'i'); - assert_eq!(c.next().unwrap().unwrap(), 'ệ'); - assert_eq!(c.next().unwrap().unwrap(), 't'); - assert!(c.next().is_none()); - } - - #[test] - #[allow(deprecated)] - fn test_read_bad_char() { - let b = &b"\x80"[..]; - let mut c = Cursor::new(b).chars(); - assert!(c.next().unwrap().is_err()); - } - #[test] fn seek_past_end() { let buf = [0xff]; diff --git a/ctr-std/src/io/error.rs b/ctr-std/src/io/error.rs index bdd675e..3e50988 100644 --- a/ctr-std/src/io/error.rs +++ b/ctr-std/src/io/error.rs @@ -83,7 +83,7 @@ enum Repr { #[derive(Debug)] struct Custom { kind: ErrorKind, - error: Box, + error: Box, } /// A list specifying general categories of I/O error. @@ -97,6 +97,7 @@ struct Custom { #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated)] +#[non_exhaustive] pub enum ErrorKind { /// An entity was not found, often a file. #[stable(feature = "rust1", since = "1.0.0")] @@ -180,15 +181,6 @@ pub enum ErrorKind { /// read. #[stable(feature = "read_exact", since = "1.6.0")] UnexpectedEof, - - /// A marker variant that tells the compiler that users of this enum cannot - /// match it exhaustively. - #[unstable(feature = "io_error_internals", - reason = "better expressed through extensible enums that this \ - enum cannot be exhaustively matched against", - issue = "0")] - #[doc(hidden)] - __Nonexhaustive, } impl ErrorKind { @@ -212,7 +204,6 @@ impl ErrorKind { ErrorKind::Interrupted => "operation interrupted", ErrorKind::Other => "other os error", ErrorKind::UnexpectedEof => "unexpected end of file", - ErrorKind::__Nonexhaustive => unreachable!() } } } @@ -250,12 +241,12 @@ impl Error { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new(kind: ErrorKind, error: E) -> Error - where E: Into> + where E: Into> { Self::_new(kind, error.into()) } - fn _new(kind: ErrorKind, error: Box) -> Error { + fn _new(kind: ErrorKind, error: Box) -> Error { Error { repr: Repr::Custom(Box::new(Custom { kind, @@ -373,7 +364,7 @@ impl Error { /// } /// ``` #[stable(feature = "io_error_inner", since = "1.3.0")] - pub fn get_ref(&self) -> Option<&(error::Error+Send+Sync+'static)> { + pub fn get_ref(&self) -> Option<&(dyn error::Error+Send+Sync+'static)> { match self.repr { Repr::Os(..) => None, Repr::Simple(..) => None, @@ -444,7 +435,7 @@ impl Error { /// } /// ``` #[stable(feature = "io_error_inner", since = "1.3.0")] - pub fn get_mut(&mut self) -> Option<&mut (error::Error+Send+Sync+'static)> { + pub fn get_mut(&mut self) -> Option<&mut (dyn error::Error+Send+Sync+'static)> { match self.repr { Repr::Os(..) => None, Repr::Simple(..) => None, @@ -478,7 +469,7 @@ impl Error { /// } /// ``` #[stable(feature = "io_error_inner", since = "1.3.0")] - pub fn into_inner(self) -> Option> { + pub fn into_inner(self) -> Option> { match self.repr { Repr::Os(..) => None, Repr::Simple(..) => None, @@ -551,7 +542,7 @@ impl error::Error for Error { } } - fn cause(&self) -> Option<&error::Error> { + fn cause(&self) -> Option<&dyn error::Error> { match self.repr { Repr::Os(..) => None, Repr::Simple(..) => None, diff --git a/ctr-std/src/io/lazy.rs b/ctr-std/src/io/lazy.rs index 9cef4e3..4fb367f 100644 --- a/ctr-std/src/io/lazy.rs +++ b/ctr-std/src/io/lazy.rs @@ -15,15 +15,21 @@ use sys_common; use sys_common::mutex::Mutex; pub struct Lazy { + // We never call `lock.init()`, so it is UB to attempt to acquire this mutex reentrantly! lock: Mutex, ptr: Cell<*mut Arc>, init: fn() -> Arc, } +#[inline] +const fn done() -> *mut Arc { 1_usize as *mut _ } + unsafe impl Sync for Lazy {} impl Lazy { - pub const fn new(init: fn() -> Arc) -> Lazy { + /// Safety: `init` must not call `get` on the variable that is being + /// initialized. + pub const unsafe fn new(init: fn() -> Arc) -> Lazy { Lazy { lock: Mutex::new(), ptr: Cell::new(ptr::null_mut()), @@ -33,32 +39,34 @@ impl Lazy { pub fn get(&'static self) -> Option> { unsafe { - self.lock.lock(); + let _guard = self.lock.lock(); let ptr = self.ptr.get(); - let ret = if ptr.is_null() { + if ptr.is_null() { Some(self.init()) - } else if ptr as usize == 1 { + } else if ptr == done() { None } else { Some((*ptr).clone()) - }; - self.lock.unlock(); - return ret + } } } + // Must only be called with `lock` held unsafe fn init(&'static self) -> Arc { // If we successfully register an at exit handler, then we cache the // `Arc` allocation in our own internal box (it will get deallocated by // the at exit handler). Otherwise we just return the freshly allocated // `Arc`. let registered = sys_common::at_exit(move || { - self.lock.lock(); - let ptr = self.ptr.get(); - self.ptr.set(1 as *mut _); - self.lock.unlock(); + let ptr = { + let _guard = self.lock.lock(); + self.ptr.replace(done()) + }; drop(Box::from_raw(ptr)) }); + // This could reentrantly call `init` again, which is a problem + // because our `lock` allows reentrancy! + // That's why `new` is unsafe and requires the caller to ensure no reentrancy happens. let ret = (self.init)(); if registered.is_ok() { self.ptr.set(Box::into_raw(Box::new(ret.clone()))); diff --git a/ctr-std/src/io/mod.rs b/ctr-std/src/io/mod.rs index eba4e9f..b83f3fb 100644 --- a/ctr-std/src/io/mod.rs +++ b/ctr-std/src/io/mod.rs @@ -147,7 +147,7 @@ //! ``` //! //! Note that you cannot use the [`?` operator] in functions that do not return -//! a [`Result`][`Result`] (e.g. `main`). Instead, you can call [`.unwrap()`] +//! a [`Result`][`Result`]. Instead, you can call [`.unwrap()`] //! or `match` on the return value to catch any possible errors: //! //! ```no_run @@ -270,10 +270,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use cmp; -use core::str as core_str; -use error as std_error; use fmt; -use result; use str; use memchr; use ptr; @@ -357,19 +354,26 @@ fn append_to_string(buf: &mut String, f: F) -> Result // avoid paying to allocate and zero a huge chunk of memory if the reader only // has 4 bytes while still making large reads if the reader does have a ton // of data to return. Simply tacking on an extra DEFAULT_BUF_SIZE space every -// time is 4,500 times (!) slower than this if the reader has a very small -// amount of data to return. +// time is 4,500 times (!) slower than a default reservation size of 32 if the +// reader has a very small amount of data to return. // // Because we're extending the buffer with uninitialized data for trusted // readers, we need to make sure to truncate that if any of this panics. fn read_to_end(r: &mut R, buf: &mut Vec) -> Result { + read_to_end_with_reservation(r, buf, 32) +} + +fn read_to_end_with_reservation(r: &mut R, + buf: &mut Vec, + reservation_size: usize) -> Result +{ let start_len = buf.len(); let mut g = Guard { len: buf.len(), buf: buf }; let ret; loop { if g.len == g.buf.len() { unsafe { - g.buf.reserve(32); + g.buf.reserve(reservation_size); let capacity = g.buf.capacity(); g.buf.set_len(capacity); r.initializer().initialize(&mut g.buf[g.len..]); @@ -800,53 +804,6 @@ pub trait Read { Bytes { inner: self } } - /// Transforms this `Read` instance to an [`Iterator`] over [`char`]s. - /// - /// This adaptor will attempt to interpret this reader as a UTF-8 encoded - /// sequence of characters. The returned iterator will return [`None`] once - /// EOF is reached for this reader. Otherwise each element yielded will be a - /// [`Result`]`<`[`char`]`, E>` where `E` may contain information about what I/O error - /// occurred or where decoding failed. - /// - /// Currently this adaptor will discard intermediate data read, and should - /// be avoided if this is not desired. - /// - /// # Examples - /// - /// [`File`]s implement `Read`: - /// - /// [`File`]: ../fs/struct.File.html - /// [`Iterator`]: ../../std/iter/trait.Iterator.html - /// [`Result`]: ../../std/result/enum.Result.html - /// [`char`]: ../../std/primitive.char.html - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// - /// ```no_run - /// #![feature(io)] - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// fn main() -> io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// - /// for c in f.chars() { - /// println!("{}", c.unwrap()); - /// } - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "io", reason = "the semantics of a partial read/write \ - of where errors happen is currently \ - unclear and may change", - issue = "27802")] - #[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead: - https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")] - #[allow(deprecated)] - fn chars(self) -> Chars where Self: Sized { - Chars { inner: self } - } - /// Creates an adaptor which will chain this stream with another. /// /// The returned `Read` instance will first read all bytes from this object @@ -1949,6 +1906,12 @@ impl Read for Take { unsafe fn initializer(&self) -> Initializer { self.inner.initializer() } + + fn read_to_end(&mut self, buf: &mut Vec) -> Result { + let reservation_size = cmp::min(self.limit, 32) as usize; + + read_to_end_with_reservation(self, buf, reservation_size) + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1972,7 +1935,7 @@ impl BufRead for Take { } } -fn read_one_byte(reader: &mut Read) -> Option> { +fn read_one_byte(reader: &mut dyn Read) -> Option> { let mut buf = [0]; loop { return match reader.read(&mut buf) { @@ -2005,104 +1968,6 @@ impl Iterator for Bytes { } } -/// An iterator over the `char`s of a reader. -/// -/// This struct is generally created by calling [`chars`][chars] on a reader. -/// Please see the documentation of `chars()` for more details. -/// -/// [chars]: trait.Read.html#method.chars -#[unstable(feature = "io", reason = "awaiting stability of Read::chars", - issue = "27802")] -#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead: - https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")] -#[derive(Debug)] -#[allow(deprecated)] -pub struct Chars { - inner: R, -} - -/// An enumeration of possible errors that can be generated from the `Chars` -/// adapter. -#[unstable(feature = "io", reason = "awaiting stability of Read::chars", - issue = "27802")] -#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead: - https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")] -#[derive(Debug)] -#[allow(deprecated)] -pub enum CharsError { - /// Variant representing that the underlying stream was read successfully - /// but it did not contain valid utf8 data. - NotUtf8, - - /// Variant representing that an I/O error occurred. - Other(Error), -} - -#[unstable(feature = "io", reason = "awaiting stability of Read::chars", - issue = "27802")] -#[allow(deprecated)] -impl Iterator for Chars { - type Item = result::Result; - - fn next(&mut self) -> Option> { - let first_byte = match read_one_byte(&mut self.inner)? { - Ok(b) => b, - Err(e) => return Some(Err(CharsError::Other(e))), - }; - let width = core_str::utf8_char_width(first_byte); - if width == 1 { return Some(Ok(first_byte as char)) } - if width == 0 { return Some(Err(CharsError::NotUtf8)) } - let mut buf = [first_byte, 0, 0, 0]; - { - let mut start = 1; - while start < width { - match self.inner.read(&mut buf[start..width]) { - Ok(0) => return Some(Err(CharsError::NotUtf8)), - Ok(n) => start += n, - Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, - Err(e) => return Some(Err(CharsError::Other(e))), - } - } - } - Some(match str::from_utf8(&buf[..width]).ok() { - Some(s) => Ok(s.chars().next().unwrap()), - None => Err(CharsError::NotUtf8), - }) - } -} - -#[unstable(feature = "io", reason = "awaiting stability of Read::chars", - issue = "27802")] -#[allow(deprecated)] -impl std_error::Error for CharsError { - fn description(&self) -> &str { - match *self { - CharsError::NotUtf8 => "invalid utf8 encoding", - CharsError::Other(ref e) => std_error::Error::description(e), - } - } - fn cause(&self) -> Option<&std_error::Error> { - match *self { - CharsError::NotUtf8 => None, - CharsError::Other(ref e) => e.cause(), - } - } -} - -#[unstable(feature = "io", reason = "awaiting stability of Read::chars", - issue = "27802")] -#[allow(deprecated)] -impl fmt::Display for CharsError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - CharsError::NotUtf8 => { - "byte stream did not contain valid utf8".fmt(f) - } - CharsError::Other(ref e) => e.fmt(f), - } - } -} - /// An iterator over the contents of an instance of `BufRead` split on a /// particular byte. /// diff --git a/ctr-std/src/io/stdio.rs b/ctr-std/src/io/stdio.rs index 2472bed..1f256f5 100644 --- a/ctr-std/src/io/stdio.rs +++ b/ctr-std/src/io/stdio.rs @@ -21,7 +21,7 @@ use thread::LocalKey; /// Stdout used by print! and println! macros thread_local! { - static LOCAL_STDOUT: RefCell>> = { + static LOCAL_STDOUT: RefCell>> = { RefCell::new(None) } } @@ -197,12 +197,13 @@ pub struct StdinLock<'a> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn stdin() -> Stdin { - static INSTANCE: Lazy>>> = Lazy::new(stdin_init); + static INSTANCE: Lazy>>> = unsafe { Lazy::new(stdin_init) }; return Stdin { inner: INSTANCE.get().expect("cannot access stdin during shutdown"), }; fn stdin_init() -> Arc>>> { + // This must not reentrantly access `INSTANCE` let stdin = match stdin_raw() { Ok(stdin) => Maybe::Real(stdin), _ => Maybe::Fake @@ -396,12 +397,13 @@ pub struct StdoutLock<'a> { #[stable(feature = "rust1", since = "1.0.0")] pub fn stdout() -> Stdout { static INSTANCE: Lazy>>>> - = Lazy::new(stdout_init); + = unsafe { Lazy::new(stdout_init) }; return Stdout { inner: INSTANCE.get().expect("cannot access stdout during shutdown"), }; fn stdout_init() -> Arc>>>> { + // This must not reentrantly access `INSTANCE` let stdout = match stdout_raw() { Ok(stdout) => Maybe::Real(stdout), _ => Maybe::Fake, @@ -531,12 +533,14 @@ pub struct StderrLock<'a> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn stderr() -> Stderr { - static INSTANCE: Lazy>>> = Lazy::new(stderr_init); + static INSTANCE: Lazy>>> = + unsafe { Lazy::new(stderr_init) }; return Stderr { inner: INSTANCE.get().expect("cannot access stderr during shutdown"), }; fn stderr_init() -> Arc>>> { + // This must not reentrantly access `INSTANCE` let stderr = match stderr_raw() { Ok(stderr) => Maybe::Real(stderr), _ => Maybe::Fake, @@ -624,7 +628,7 @@ impl<'a> fmt::Debug for StderrLock<'a> { with a more general mechanism", issue = "0")] #[doc(hidden)] -pub fn set_panic(sink: Option>) -> Option> { +pub fn set_panic(sink: Option>) -> Option> { use panicking::LOCAL_STDERR; use mem; LOCAL_STDERR.with(move |slot| { @@ -648,7 +652,7 @@ pub fn set_panic(sink: Option>) -> Option> { with a more general mechanism", issue = "0")] #[doc(hidden)] -pub fn set_print(sink: Option>) -> Option> { +pub fn set_print(sink: Option>) -> Option> { use mem; LOCAL_STDOUT.with(move |slot| { mem::replace(&mut *slot.borrow_mut(), sink) @@ -670,7 +674,7 @@ pub fn set_print(sink: Option>) -> Option> { /// However, if the actual I/O causes an error, this function does panic. fn print_to( args: fmt::Arguments, - local_s: &'static LocalKey>>>, + local_s: &'static LocalKey>>>, global_s: fn() -> T, label: &str, ) @@ -712,9 +716,31 @@ pub fn _eprint(args: fmt::Arguments) { #[cfg(test)] mod tests { + use panic::{UnwindSafe, RefUnwindSafe}; use thread; use super::*; + #[test] + fn stdout_unwind_safe() { + assert_unwind_safe::(); + } + #[test] + fn stdoutlock_unwind_safe() { + assert_unwind_safe::(); + assert_unwind_safe::>(); + } + #[test] + fn stderr_unwind_safe() { + assert_unwind_safe::(); + } + #[test] + fn stderrlock_unwind_safe() { + assert_unwind_safe::(); + assert_unwind_safe::>(); + } + + fn assert_unwind_safe() {} + #[test] #[cfg_attr(target_os = "emscripten", ignore)] fn panic_doesnt_poison() { diff --git a/ctr-std/src/io/util.rs b/ctr-std/src/io/util.rs index 195310a..33f741d 100644 --- a/ctr-std/src/io/util.rs +++ b/ctr-std/src/io/util.rs @@ -223,7 +223,7 @@ mod tests { assert_eq!(copy(&mut r, &mut w).unwrap(), 4); let mut r = repeat(0).take(1 << 17); - assert_eq!(copy(&mut r as &mut Read, &mut w as &mut Write).unwrap(), 1 << 17); + assert_eq!(copy(&mut r as &mut dyn Read, &mut w as &mut dyn Write).unwrap(), 1 << 17); } #[test] diff --git a/ctr-std/src/keyword_docs.rs b/ctr-std/src/keyword_docs.rs new file mode 100644 index 0000000..4f6bda6 --- /dev/null +++ b/ctr-std/src/keyword_docs.rs @@ -0,0 +1,58 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[doc(keyword = "fn")] +// +/// The `fn` keyword. +/// +/// The `fn` keyword is used to declare a function. +/// +/// Example: +/// +/// ```rust +/// fn some_function() { +/// // code goes in here +/// } +/// ``` +/// +/// For more information about functions, take a look at the [Rust Book][book]. +/// +/// [book]: https://doc.rust-lang.org/book/second-edition/ch03-03-how-functions-work.html +mod fn_keyword { } + +#[doc(keyword = "let")] +// +/// The `let` keyword. +/// +/// The `let` keyword is used to declare a variable. +/// +/// Example: +/// +/// ```rust +/// # #![allow(unused_assignments)] +/// let x = 3; // We create a variable named `x` with the value `3`. +/// ``` +/// +/// By default, all variables are **not** mutable. If you want a mutable variable, +/// you'll have to use the `mut` keyword. +/// +/// Example: +/// +/// ```rust +/// # #![allow(unused_assignments)] +/// let mut x = 3; // We create a mutable variable named `x` with the value `3`. +/// +/// x += 4; // `x` is now equal to `7`. +/// ``` +/// +/// For more information about the `let` keyword, take a look at the [Rust Book][book]. +/// +/// [book]: https://doc.rust-lang.org/book/second-edition/ch03-01-variables-and-mutability.html +mod let_keyword { } diff --git a/ctr-std/src/lib.rs b/ctr-std/src/lib.rs index 7248a10..19ea930 100644 --- a/ctr-std/src/lib.rs +++ b/ctr-std/src/lib.rs @@ -232,15 +232,16 @@ // std is implemented with unstable features, many of which are internal // compiler details that will never be stable +#![cfg_attr(test, feature(test, update_panic_count))] #![feature(alloc)] +#![feature(alloc_error_handler)] #![feature(allocator_api)] -#![feature(alloc_system)] #![feature(allocator_internals)] #![feature(allow_internal_unsafe)] #![feature(allow_internal_unstable)] #![feature(align_offset)] +#![feature(arbitrary_self_types)] #![feature(array_error_internals)] -#![feature(ascii_ctype)] #![feature(asm)] #![feature(attr_literals)] #![feature(box_syntax)] @@ -248,25 +249,22 @@ #![feature(cfg_target_thread_local)] #![feature(cfg_target_vendor)] #![feature(char_error_internals)] -#![feature(char_internals)] -#![feature(collections_range)] #![feature(compiler_builtins_lib)] #![feature(const_fn)] +#![feature(const_int_ops)] +#![feature(const_ip)] #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] #![feature(exact_size_is_empty)] #![feature(external_doc)] -#![feature(fs_read_write)] #![feature(fixed_size_array)] -#![feature(float_from_str_radix)] #![feature(fn_traits)] #![feature(fnbox)] #![feature(futures_api)] +#![feature(generator_trait)] #![feature(hashmap_internals)] -#![feature(heap_api)] #![feature(int_error_internals)] #![feature(integer_atomics)] -#![feature(into_cow)] #![feature(lang_items)] #![feature(libc)] #![feature(link_args)] @@ -274,35 +272,28 @@ #![feature(macro_vis_matcher)] #![feature(needs_panic_runtime)] #![feature(never_type)] +#![cfg_attr(not(stage0), feature(nll))] #![feature(exhaustive_patterns)] -#![feature(num_bits_bytes)] -#![feature(old_wrapping)] #![feature(on_unimplemented)] -#![feature(oom)] #![feature(optin_builtin_traits)] #![feature(panic_internals)] #![feature(panic_unwind)] -#![feature(peek)] #![feature(pin)] -#![feature(placement_new_protocol)] #![feature(prelude_import)] #![feature(ptr_internals)] -#![feature(rand)] #![feature(raw)] #![feature(rustc_attrs)] +#![feature(rustc_const_unstable)] #![feature(std_internals)] #![feature(stdsimd)] #![feature(shrink_to)] -#![feature(slice_bytes)] #![feature(slice_concat_ext)] #![feature(slice_internals)] #![feature(slice_patterns)] #![feature(staged_api)] #![feature(stmt_expr_attributes)] -#![feature(str_char)] #![feature(str_internals)] -#![feature(str_utf16)] -#![feature(test, rustc_private)] +#![feature(rustc_private)] #![feature(thread_local)] #![feature(toowned_clone_into)] #![feature(try_from)] @@ -310,18 +301,16 @@ #![feature(unboxed_closures)] #![feature(untagged_unions)] #![feature(unwind_attributes)] -#![feature(use_extern_macros)] -#![feature(vec_push_all)] +#![cfg_attr(stage0, feature(use_extern_macros))] #![feature(doc_cfg)] #![feature(doc_masked)] #![feature(doc_spotlight)] -#![cfg_attr(test, feature(update_panic_count))] #![cfg_attr(windows, feature(used))] #![feature(doc_alias)] #![feature(doc_keyword)] -#![feature(float_internals)] #![feature(panic_info_message)] -#![cfg_attr(not(stage0), feature(panic_implementation))] +#![feature(panic_implementation)] +#![feature(non_exhaustive)] #![default_lib_allocator] @@ -331,9 +320,6 @@ // `force_alloc_system` is *only* intended as a workaround for local rebuilds // with a rustc without jemalloc. // FIXME(#44236) shouldn't need MSVC logic -#![cfg_attr(all(not(target_env = "msvc"), - any(all(stage0, not(test)), feature = "force_alloc_system")), - feature(global_allocator))] #[cfg(all(not(target_env = "msvc"), any(all(stage0, not(test)), feature = "force_alloc_system")))] #[global_allocator] @@ -465,20 +451,6 @@ pub use core::u128; #[stable(feature = "core_hint", since = "1.27.0")] pub use core::hint; -#[unstable(feature = "futures_api", - reason = "futures in libcore are unstable", - issue = "50547")] -pub mod task { - //! Types and Traits for working with asynchronous tasks. - pub use core::task::*; - pub use alloc_crate::task::*; -} - -#[unstable(feature = "futures_api", - reason = "futures in libcore are unstable", - issue = "50547")] -pub use core::future; - pub mod f32; pub mod f64; @@ -500,13 +472,22 @@ pub mod process; pub mod sync; pub mod time; -#[unstable(feature = "allocator_api", issue = "32838")] -#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")] -/// Use the `alloc` module instead. -pub mod heap { - pub use alloc::*; +#[unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] +pub mod task { + //! Types and Traits for working with asynchronous tasks. + #[doc(inline)] + pub use core::task::*; + #[doc(inline)] + pub use alloc_crate::task::*; } +#[unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] +pub mod future; + // Platform-abstraction modules #[macro_use] mod sys_common; @@ -526,3 +507,8 @@ pub mod rt; // the rustdoc documentation for primitive types. Using `include!` // because rustdoc only looks for these modules at the crate level. include!("primitive_docs.rs"); + +// Include a number of private modules that exist solely to provide +// the rustdoc documentation for the existing keywords. Using `include!` +// because rustdoc only looks for these modules at the crate level. +include!("keyword_docs.rs"); diff --git a/ctr-std/src/macros.rs b/ctr-std/src/macros.rs index 8da70f5..f15494c 100644 --- a/ctr-std/src/macros.rs +++ b/ctr-std/src/macros.rs @@ -38,10 +38,13 @@ /// The multi-argument form of this macro panics with a string and has the /// [`format!`] syntax for building a string. /// +/// See also the macro [`compile_error!`], for raising errors during compilation. +/// /// [runwrap]: ../std/result/enum.Result.html#method.unwrap /// [`Option`]: ../std/option/enum.Option.html#method.unwrap /// [`Result`]: ../std/result/enum.Result.html /// [`format!`]: ../std/macro.format.html +/// [`compile_error!`]: ../std/macro.compile_error.html /// [book]: ../book/second-edition/ch09-01-unrecoverable-errors-with-panic.html /// /// # Current implementation @@ -150,10 +153,12 @@ macro_rules! print { /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] +#[allow_internal_unstable] macro_rules! println { () => (print!("\n")); - ($fmt:expr) => (print!(concat!($fmt, "\n"))); - ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*)); + ($($arg:tt)*) => ({ + $crate::io::_print(format_args_nl!($($arg)*)); + }) } /// Macro for printing to the standard error. @@ -207,10 +212,34 @@ macro_rules! eprint { /// ``` #[macro_export] #[stable(feature = "eprint", since = "1.19.0")] +#[allow_internal_unstable] macro_rules! eprintln { () => (eprint!("\n")); - ($fmt:expr) => (eprint!(concat!($fmt, "\n"))); - ($fmt:expr, $($arg:tt)*) => (eprint!(concat!($fmt, "\n"), $($arg)*)); + ($($arg:tt)*) => ({ + $crate::io::_eprint(format_args_nl!($($arg)*)); + }) +} + +#[macro_export] +#[unstable(feature = "await_macro", issue = "50547")] +#[allow_internal_unstable] +#[allow_internal_unsafe] +macro_rules! await { + ($e:expr) => { { + let mut pinned = $e; + loop { + if let $crate::task::Poll::Ready(x) = + $crate::future::poll_in_task_cx(unsafe { + $crate::mem::PinMut::new_unchecked(&mut pinned) + }) + { + break x; + } + // FIXME(cramertj) prior to stabilizing await, we have to ensure that this + // can't be used to create a generator on stable via `|| await!()`. + yield + } + } } } /// A macro to select an event from a number of receivers. @@ -281,18 +310,21 @@ macro_rules! assert_approx_eq { /// macro, but are documented here. Their implementations can be found hardcoded /// into libsyntax itself. #[cfg(dox)] -pub mod builtin { +mod builtin { /// Unconditionally causes compilation to fail with the given error message when encountered. /// /// This macro should be used when a crate uses a conditional compilation strategy to provide - /// better error messages for erroneous conditions. + /// better error messages for erroneous conditions. It's the compiler-level form of [`panic!`], + /// which emits an error at *runtime*, rather than during compilation. /// /// # Examples /// /// Two such examples are macros and `#[cfg]` environments. /// - /// Emit better compiler error if a macro is passed invalid values. + /// Emit better compiler error if a macro is passed invalid values. Without the final branch, + /// the compiler would still emit an error, but the error's message would not mention the two + /// valid values. /// /// ```compile_fail /// macro_rules! give_me_foo_or_bar { @@ -313,8 +345,10 @@ pub mod builtin { /// #[cfg(not(any(feature = "foo", feature = "bar")))] /// compile_error!("Either feature \"foo\" or \"bar\" must be enabled for this crate.") /// ``` + /// + /// [`panic!`]: ../std/macro.panic.html #[stable(feature = "compile_error_macro", since = "1.20.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! compile_error { ($msg:expr) => ({ /* compiler built-in */ }); ($msg:expr,) => ({ /* compiler built-in */ }); @@ -366,7 +400,7 @@ pub mod builtin { /// assert_eq!(s, format!("hello {}", "world")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! format_args { ($fmt:expr) => ({ /* compiler built-in */ }); ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }); @@ -404,7 +438,7 @@ pub mod builtin { /// error: what's that?! /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! env { ($name:expr) => ({ /* compiler built-in */ }); ($name:expr,) => ({ /* compiler built-in */ }); @@ -430,7 +464,7 @@ pub mod builtin { /// println!("the secret key might be: {:?}", key); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! option_env { ($name:expr) => ({ /* compiler built-in */ }); ($name:expr,) => ({ /* compiler built-in */ }); @@ -461,7 +495,7 @@ pub mod builtin { /// # } /// ``` #[unstable(feature = "concat_idents_macro", issue = "29599")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! concat_idents { ($($e:ident),+) => ({ /* compiler built-in */ }); ($($e:ident,)+) => ({ /* compiler built-in */ }); @@ -483,7 +517,7 @@ pub mod builtin { /// assert_eq!(s, "test10btrue"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! concat { ($($e:expr),*) => ({ /* compiler built-in */ }); ($($e:expr,)*) => ({ /* compiler built-in */ }); @@ -511,7 +545,7 @@ pub mod builtin { /// println!("defined on line: {}", current_line); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! line { () => ({ /* compiler built-in */ }) } /// A macro which expands to the column number on which it was invoked. @@ -536,7 +570,7 @@ pub mod builtin { /// println!("defined on column: {}", current_col); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! column { () => ({ /* compiler built-in */ }) } /// A macro which expands to the file name from which it was invoked. @@ -560,7 +594,7 @@ pub mod builtin { /// println!("defined in file: {}", this_file); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! file { () => ({ /* compiler built-in */ }) } /// A macro which stringifies its arguments. @@ -579,7 +613,7 @@ pub mod builtin { /// assert_eq!(one_plus_one, "1 + 1"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! stringify { ($($t:tt)*) => ({ /* compiler built-in */ }) } /// Includes a utf8-encoded file as a string. @@ -613,7 +647,7 @@ pub mod builtin { /// /// Compiling 'main.rs' and running the resulting binary will print "adiós". #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! include_str { ($file:expr) => ({ /* compiler built-in */ }); ($file:expr,) => ({ /* compiler built-in */ }); @@ -650,7 +684,7 @@ pub mod builtin { /// /// Compiling 'main.rs' and running the resulting binary will print "adiós". #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! include_bytes { ($file:expr) => ({ /* compiler built-in */ }); ($file:expr,) => ({ /* compiler built-in */ }); @@ -674,7 +708,7 @@ pub mod builtin { /// test::foo(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! module_path { () => ({ /* compiler built-in */ }) } /// Boolean evaluation of configuration flags, at compile-time. @@ -696,7 +730,7 @@ pub mod builtin { /// }; /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! cfg { ($($cfg:tt)*) => ({ /* compiler built-in */ }) } /// Parse a file as an expression or an item according to the context. @@ -739,7 +773,7 @@ pub mod builtin { /// Compiling 'main.rs' and running the resulting binary will print /// "🙈🙊🙉🙈🙊🙉". #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! include { ($file:expr) => ({ /* compiler built-in */ }); ($file:expr,) => ({ /* compiler built-in */ }); @@ -792,7 +826,7 @@ pub mod builtin { /// assert!(a + b == 30, "a = {}, b = {}", a, b); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! assert { ($cond:expr) => ({ /* compiler built-in */ }); ($cond:expr,) => ({ /* compiler built-in */ }); diff --git a/ctr-std/src/net/ip.rs b/ctr-std/src/net/ip.rs index fcec8d0..9a610cd 100644 --- a/ctr-std/src/net/ip.rs +++ b/ctr-std/src/net/ip.rs @@ -16,8 +16,6 @@ use cmp::Ordering; use fmt; use hash; -use mem; -use net::{hton, ntoh}; use sys::net::netc as c; use sys_common::{AsInner, FromInner}; @@ -162,9 +160,9 @@ impl IpAddr { /// ``` #[stable(feature = "ip_shared", since = "1.12.0")] pub fn is_unspecified(&self) -> bool { - match *self { - IpAddr::V4(ref a) => a.is_unspecified(), - IpAddr::V6(ref a) => a.is_unspecified(), + match self { + IpAddr::V4(ip) => ip.is_unspecified(), + IpAddr::V6(ip) => ip.is_unspecified(), } } @@ -187,9 +185,9 @@ impl IpAddr { /// ``` #[stable(feature = "ip_shared", since = "1.12.0")] pub fn is_loopback(&self) -> bool { - match *self { - IpAddr::V4(ref a) => a.is_loopback(), - IpAddr::V6(ref a) => a.is_loopback(), + match self { + IpAddr::V4(ip) => ip.is_loopback(), + IpAddr::V6(ip) => ip.is_loopback(), } } @@ -216,9 +214,9 @@ impl IpAddr { /// } /// ``` pub fn is_global(&self) -> bool { - match *self { - IpAddr::V4(ref a) => a.is_global(), - IpAddr::V6(ref a) => a.is_global(), + match self { + IpAddr::V4(ip) => ip.is_global(), + IpAddr::V6(ip) => ip.is_global(), } } @@ -241,9 +239,9 @@ impl IpAddr { /// ``` #[stable(feature = "ip_shared", since = "1.12.0")] pub fn is_multicast(&self) -> bool { - match *self { - IpAddr::V4(ref a) => a.is_multicast(), - IpAddr::V6(ref a) => a.is_multicast(), + match self { + IpAddr::V4(ip) => ip.is_multicast(), + IpAddr::V6(ip) => ip.is_multicast(), } } @@ -270,9 +268,9 @@ impl IpAddr { /// } /// ``` pub fn is_documentation(&self) -> bool { - match *self { - IpAddr::V4(ref a) => a.is_documentation(), - IpAddr::V6(ref a) => a.is_documentation(), + match self { + IpAddr::V4(ip) => ip.is_documentation(), + IpAddr::V6(ip) => ip.is_documentation(), } } @@ -295,7 +293,7 @@ impl IpAddr { /// ``` #[stable(feature = "ipaddr_checker", since = "1.16.0")] pub fn is_ipv4(&self) -> bool { - match *self { + match self { IpAddr::V4(_) => true, IpAddr::V6(_) => false, } @@ -320,7 +318,7 @@ impl IpAddr { /// ``` #[stable(feature = "ipaddr_checker", since = "1.16.0")] pub fn is_ipv6(&self) -> bool { - match *self { + match self { IpAddr::V4(_) => false, IpAddr::V6(_) => true, } @@ -340,18 +338,21 @@ impl Ipv4Addr { /// let addr = Ipv4Addr::new(127, 0, 0, 1); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { + #[rustc_const_unstable(feature = "const_ip")] + pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr { Ipv4Addr { inner: c::in_addr { - s_addr: hton(((a as u32) << 24) | - ((b as u32) << 16) | - ((c as u32) << 8) | - (d as u32)), + s_addr: u32::to_be( + ((a as u32) << 24) | + ((b as u32) << 16) | + ((c as u32) << 8) | + (d as u32) + ), } } } - /// Creates a new IPv4 address with the address pointing to localhost: 127.0.0.1. + /// An IPv4 address with the address pointing to localhost: 127.0.0.1. /// /// # Examples /// @@ -359,17 +360,15 @@ impl Ipv4Addr { /// #![feature(ip_constructors)] /// use std::net::Ipv4Addr; /// - /// let addr = Ipv4Addr::localhost(); + /// let addr = Ipv4Addr::LOCALHOST; /// assert_eq!(addr, Ipv4Addr::new(127, 0, 0, 1)); /// ``` #[unstable(feature = "ip_constructors", reason = "requires greater scrutiny before stabilization", issue = "44582")] - pub fn localhost() -> Ipv4Addr { - Ipv4Addr::new(127, 0, 0, 1) - } + pub const LOCALHOST: Self = Ipv4Addr::new(127, 0, 0, 1); - /// Creates a new IPv4 address representing an unspecified address: 0.0.0.0 + /// An IPv4 address representing an unspecified address: 0.0.0.0 /// /// # Examples /// @@ -377,15 +376,29 @@ impl Ipv4Addr { /// #![feature(ip_constructors)] /// use std::net::Ipv4Addr; /// - /// let addr = Ipv4Addr::unspecified(); + /// let addr = Ipv4Addr::UNSPECIFIED; /// assert_eq!(addr, Ipv4Addr::new(0, 0, 0, 0)); /// ``` #[unstable(feature = "ip_constructors", reason = "requires greater scrutiny before stabilization", issue = "44582")] - pub fn unspecified() -> Ipv4Addr { - Ipv4Addr::new(0, 0, 0, 0) - } + pub const UNSPECIFIED: Self = Ipv4Addr::new(0, 0, 0, 0); + + /// An IPv4 address representing the broadcast address: 255.255.255.255 + /// + /// # Examples + /// + /// ``` + /// #![feature(ip_constructors)] + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::BROADCAST; + /// assert_eq!(addr, Ipv4Addr::new(255, 255, 255, 255)); + /// ``` + #[unstable(feature = "ip_constructors", + reason = "requires greater scrutiny before stabilization", + issue = "44582")] + pub const BROADCAST: Self = Ipv4Addr::new(255, 255, 255, 255); /// Returns the four eight-bit integers that make up this address. /// @@ -399,7 +412,7 @@ impl Ipv4Addr { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn octets(&self) -> [u8; 4] { - let bits = ntoh(self.inner.s_addr); + let bits = u32::from_be(self.inner.s_addr); [(bits >> 24) as u8, (bits >> 16) as u8, (bits >> 8) as u8, bits as u8] } @@ -470,11 +483,11 @@ impl Ipv4Addr { /// ``` #[stable(since = "1.7.0", feature = "ip_17")] pub fn is_private(&self) -> bool { - match (self.octets()[0], self.octets()[1]) { - (10, _) => true, - (172, b) if b >= 16 && b <= 31 => true, - (192, 168) => true, - _ => false + match self.octets() { + [10, ..] => true, + [172, b, ..] if b >= 16 && b <= 31 => true, + [192, 168, ..] => true, + _ => false, } } @@ -496,7 +509,10 @@ impl Ipv4Addr { /// ``` #[stable(since = "1.7.0", feature = "ip_17")] pub fn is_link_local(&self) -> bool { - self.octets()[0] == 169 && self.octets()[1] == 254 + match self.octets() { + [169, 254, ..] => true, + _ => false, + } } /// Returns [`true`] if the address appears to be globally routable. @@ -573,8 +589,7 @@ impl Ipv4Addr { /// ``` #[stable(since = "1.7.0", feature = "ip_17")] pub fn is_broadcast(&self) -> bool { - self.octets()[0] == 255 && self.octets()[1] == 255 && - self.octets()[2] == 255 && self.octets()[3] == 255 + self == &Self::BROADCAST } /// Returns [`true`] if this address is in a range designated for documentation. @@ -600,11 +615,11 @@ impl Ipv4Addr { /// ``` #[stable(since = "1.7.0", feature = "ip_17")] pub fn is_documentation(&self) -> bool { - match(self.octets()[0], self.octets()[1], self.octets()[2], self.octets()[3]) { - (192, 0, 2, _) => true, - (198, 51, 100, _) => true, - (203, 0, 113, _) => true, - _ => false + match self.octets() { + [192, 0, 2, _] => true, + [198, 51, 100, _] => true, + [203, 0, 113, _] => true, + _ => false, } } @@ -654,9 +669,9 @@ impl Ipv4Addr { #[stable(feature = "ip_addr", since = "1.7.0")] impl fmt::Display for IpAddr { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - match *self { - IpAddr::V4(ref a) => a.fmt(fmt), - IpAddr::V6(ref a) => a.fmt(fmt), + match self { + IpAddr::V4(ip) => ip.fmt(fmt), + IpAddr::V6(ip) => ip.fmt(fmt), } } } @@ -705,8 +720,8 @@ impl PartialEq for Ipv4Addr { #[stable(feature = "ip_cmp", since = "1.16.0")] impl PartialEq for IpAddr { fn eq(&self, other: &Ipv4Addr) -> bool { - match *self { - IpAddr::V4(ref v4) => v4 == other, + match self { + IpAddr::V4(v4) => v4 == other, IpAddr::V6(_) => false, } } @@ -715,8 +730,8 @@ impl PartialEq for IpAddr { #[stable(feature = "ip_cmp", since = "1.16.0")] impl PartialEq for Ipv4Addr { fn eq(&self, other: &IpAddr) -> bool { - match *other { - IpAddr::V4(ref v4) => self == v4, + match other { + IpAddr::V4(v4) => self == v4, IpAddr::V6(_) => false, } } @@ -743,8 +758,8 @@ impl PartialOrd for Ipv4Addr { #[stable(feature = "ip_cmp", since = "1.16.0")] impl PartialOrd for IpAddr { fn partial_cmp(&self, other: &Ipv4Addr) -> Option { - match *self { - IpAddr::V4(ref v4) => v4.partial_cmp(other), + match self { + IpAddr::V4(v4) => v4.partial_cmp(other), IpAddr::V6(_) => Some(Ordering::Greater), } } @@ -753,8 +768,8 @@ impl PartialOrd for IpAddr { #[stable(feature = "ip_cmp", since = "1.16.0")] impl PartialOrd for Ipv4Addr { fn partial_cmp(&self, other: &IpAddr) -> Option { - match *other { - IpAddr::V4(ref v4) => self.partial_cmp(v4), + match other { + IpAddr::V4(v4) => self.partial_cmp(v4), IpAddr::V6(_) => Some(Ordering::Less), } } @@ -763,7 +778,7 @@ impl PartialOrd for Ipv4Addr { #[stable(feature = "rust1", since = "1.0.0")] impl Ord for Ipv4Addr { fn cmp(&self, other: &Ipv4Addr) -> Ordering { - ntoh(self.inner.s_addr).cmp(&ntoh(other.inner.s_addr)) + u32::from_be(self.inner.s_addr).cmp(&u32::from_be(other.inner.s_addr)) } } @@ -856,21 +871,27 @@ impl Ipv6Addr { /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, - h: u16) -> Ipv6Addr { - let mut addr: c::in6_addr = unsafe { mem::zeroed() }; - addr.s6_addr = [(a >> 8) as u8, a as u8, - (b >> 8) as u8, b as u8, - (c >> 8) as u8, c as u8, - (d >> 8) as u8, d as u8, - (e >> 8) as u8, e as u8, - (f >> 8) as u8, f as u8, - (g >> 8) as u8, g as u8, - (h >> 8) as u8, h as u8]; - Ipv6Addr { inner: addr } + #[rustc_const_unstable(feature = "const_ip")] + pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, + g: u16, h: u16) -> Ipv6Addr { + Ipv6Addr { + inner: c::in6_addr { + s6_addr: [ + (a >> 8) as u8, a as u8, + (b >> 8) as u8, b as u8, + (c >> 8) as u8, c as u8, + (d >> 8) as u8, d as u8, + (e >> 8) as u8, e as u8, + (f >> 8) as u8, f as u8, + (g >> 8) as u8, g as u8, + (h >> 8) as u8, h as u8 + ], + } + } + } - /// Creates a new IPv6 address representing localhost: `::1`. + /// An IPv6 address representing localhost: `::1`. /// /// # Examples /// @@ -878,17 +899,15 @@ impl Ipv6Addr { /// #![feature(ip_constructors)] /// use std::net::Ipv6Addr; /// - /// let addr = Ipv6Addr::localhost(); + /// let addr = Ipv6Addr::LOCALHOST; /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); /// ``` #[unstable(feature = "ip_constructors", reason = "requires greater scrutiny before stabilization", issue = "44582")] - pub fn localhost() -> Ipv6Addr { - Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1) - } + pub const LOCALHOST: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); - /// Creates a new IPv6 address representing the unspecified address: `::` + /// An IPv6 address representing the unspecified address: `::` /// /// # Examples /// @@ -896,15 +915,13 @@ impl Ipv6Addr { /// #![feature(ip_constructors)] /// use std::net::Ipv6Addr; /// - /// let addr = Ipv6Addr::unspecified(); + /// let addr = Ipv6Addr::UNSPECIFIED; /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); /// ``` #[unstable(feature = "ip_constructors", reason = "requires greater scrutiny before stabilization", issue = "44582")] - pub fn unspecified() -> Ipv6Addr { - Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0) - } + pub const UNSPECIFIED: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); /// Returns the eight 16-bit segments that make up this address. /// @@ -1321,9 +1338,9 @@ impl PartialEq for Ipv6Addr { #[stable(feature = "ip_cmp", since = "1.16.0")] impl PartialEq for Ipv6Addr { fn eq(&self, other: &IpAddr) -> bool { - match *other { + match other { IpAddr::V4(_) => false, - IpAddr::V6(ref v6) => self == v6, + IpAddr::V6(v6) => self == v6, } } } @@ -1331,9 +1348,9 @@ impl PartialEq for Ipv6Addr { #[stable(feature = "ip_cmp", since = "1.16.0")] impl PartialEq for IpAddr { fn eq(&self, other: &Ipv6Addr) -> bool { - match *self { + match self { IpAddr::V4(_) => false, - IpAddr::V6(ref v6) => v6 == other, + IpAddr::V6(v6) => v6 == other, } } } @@ -1358,9 +1375,9 @@ impl PartialOrd for Ipv6Addr { #[stable(feature = "ip_cmp", since = "1.16.0")] impl PartialOrd for IpAddr { fn partial_cmp(&self, other: &Ipv6Addr) -> Option { - match *self { + match self { IpAddr::V4(_) => Some(Ordering::Less), - IpAddr::V6(ref v6) => v6.partial_cmp(other), + IpAddr::V6(v6) => v6.partial_cmp(other), } } } @@ -1368,9 +1385,9 @@ impl PartialOrd for IpAddr { #[stable(feature = "ip_cmp", since = "1.16.0")] impl PartialOrd for Ipv6Addr { fn partial_cmp(&self, other: &IpAddr) -> Option { - match *other { + match other { IpAddr::V4(_) => Some(Ordering::Greater), - IpAddr::V6(ref v6) => self.partial_cmp(v6), + IpAddr::V6(v6) => self.partial_cmp(v6), } } } @@ -1414,8 +1431,7 @@ impl From for Ipv6Addr { #[stable(feature = "ipv6_from_octets", since = "1.9.0")] impl From<[u8; 16]> for Ipv6Addr { fn from(octets: [u8; 16]) -> Ipv6Addr { - let mut inner: c::in6_addr = unsafe { mem::zeroed() }; - inner.s6_addr = octets; + let inner = c::in6_addr { s6_addr: octets }; Ipv6Addr::from_inner(inner) } } @@ -1846,18 +1862,20 @@ mod tests { #[test] fn ipv4_from_constructors() { - assert_eq!(Ipv4Addr::localhost(), Ipv4Addr::new(127, 0, 0, 1)); - assert!(Ipv4Addr::localhost().is_loopback()); - assert_eq!(Ipv4Addr::unspecified(), Ipv4Addr::new(0, 0, 0, 0)); - assert!(Ipv4Addr::unspecified().is_unspecified()); + assert_eq!(Ipv4Addr::LOCALHOST, Ipv4Addr::new(127, 0, 0, 1)); + assert!(Ipv4Addr::LOCALHOST.is_loopback()); + assert_eq!(Ipv4Addr::UNSPECIFIED, Ipv4Addr::new(0, 0, 0, 0)); + assert!(Ipv4Addr::UNSPECIFIED.is_unspecified()); + assert_eq!(Ipv4Addr::BROADCAST, Ipv4Addr::new(255, 255, 255, 255)); + assert!(Ipv4Addr::BROADCAST.is_broadcast()); } #[test] fn ipv6_from_contructors() { - assert_eq!(Ipv6Addr::localhost(), Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); - assert!(Ipv6Addr::localhost().is_loopback()); - assert_eq!(Ipv6Addr::unspecified(), Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); - assert!(Ipv6Addr::unspecified().is_unspecified()); + assert_eq!(Ipv6Addr::LOCALHOST, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); + assert!(Ipv6Addr::LOCALHOST.is_loopback()); + assert_eq!(Ipv6Addr::UNSPECIFIED, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); + assert!(Ipv6Addr::UNSPECIFIED.is_unspecified()); } #[test] diff --git a/ctr-std/src/net/parser.rs b/ctr-std/src/net/parser.rs index ae5037c..cf3e535 100644 --- a/ctr-std/src/net/parser.rs +++ b/ctr-std/src/net/parser.rs @@ -53,15 +53,12 @@ impl<'a> Parser<'a> { F: FnOnce(&mut Parser) -> Option, { self.read_atomically(move |p| { - match cb(p) { - Some(x) => if p.is_eof() {Some(x)} else {None}, - None => None, - } + cb(p).filter(|_| p.is_eof()) }) } // Return result of first successful parser - fn read_or(&mut self, parsers: &mut [Box Option + 'static>]) + fn read_or(&mut self, parsers: &mut [Box Option + 'static>]) -> Option { for pf in parsers { if let Some(r) = self.read_atomically(|p: &mut Parser| pf(p)) { diff --git a/ctr-std/src/net/tcp.rs b/ctr-std/src/net/tcp.rs index 0f60b5b..75c7a3d 100644 --- a/ctr-std/src/net/tcp.rs +++ b/ctr-std/src/net/tcp.rs @@ -81,7 +81,7 @@ pub struct TcpStream(net_imp::TcpStream); /// } /// /// fn main() -> io::Result<()> { -/// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); +/// let listener = TcpListener::bind("127.0.0.1:80")?; /// /// // accept connections and process them serially /// for stream in listener.incoming() { @@ -927,7 +927,7 @@ mod tests { use time::{Instant, Duration}; use thread; - fn each_ip(f: &mut FnMut(SocketAddr)) { + fn each_ip(f: &mut dyn FnMut(SocketAddr)) { f(next_test_ip4()); f(next_test_ip6()); } diff --git a/ctr-std/src/net/udp.rs b/ctr-std/src/net/udp.rs index d25e299..0ebe328 100644 --- a/ctr-std/src/net/udp.rs +++ b/ctr-std/src/net/udp.rs @@ -826,7 +826,7 @@ mod tests { use time::{Instant, Duration}; use thread; - fn each_ip(f: &mut FnMut(SocketAddr, SocketAddr)) { + fn each_ip(f: &mut dyn FnMut(SocketAddr, SocketAddr)) { f(next_test_ip4(), next_test_ip4()); f(next_test_ip6(), next_test_ip6()); } diff --git a/ctr-std/src/os/hermit/fs.rs b/ctr-std/src/os/hermit/fs.rs new file mode 100644 index 0000000..d2e7516 --- /dev/null +++ b/ctr-std/src/os/hermit/fs.rs @@ -0,0 +1,389 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![stable(feature = "metadata_ext", since = "1.1.0")] + +use libc; + +use fs::Metadata; +use sys_common::AsInner; + +#[allow(deprecated)] +use os::hermit::raw; + +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html +#[stable(feature = "metadata_ext", since = "1.1.0")] +pub trait MetadataExt { + /// Gain a reference to the underlying `stat` structure which contains + /// the raw information returned by the OS. + /// + /// The contents of the returned [`stat`] are **not** consistent across + /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the + /// cross-Unix abstractions contained within the raw stat. + /// + /// [`stat`]: ../../../../std/os/linux/raw/struct.stat.html + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let stat = meta.as_raw_stat(); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext", since = "1.1.0")] + #[rustc_deprecated(since = "1.8.0", + reason = "deprecated in favor of the accessor \ + methods of this trait")] + #[allow(deprecated)] + fn as_raw_stat(&self) -> &raw::stat; + + /// Returns the device ID on which this file resides. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_dev()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_dev(&self) -> u64; + /// Returns the inode number. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_ino()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ino(&self) -> u64; + /// Returns the file type and mode. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_mode()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mode(&self) -> u32; + /// Returns the number of hard links to file. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_nlink()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_nlink(&self) -> u64; + /// Returns the user ID of the file owner. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_uid()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_uid(&self) -> u32; + /// Returns the group ID of the file owner. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_gid()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_gid(&self) -> u32; + /// Returns the device ID that this file represents. Only relevant for special file. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_rdev()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_rdev(&self) -> u64; + /// Returns the size of the file (if it is a regular file or a symbolic link) in bytes. + /// + /// The size of a symbolic link is the length of the pathname it contains, + /// without a terminating null byte. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_size()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_size(&self) -> u64; + /// Returns the last access time. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_atime()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime(&self) -> i64; + /// Returns the last access time, nano seconds part. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_atime_nsec()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime_nsec(&self) -> i64; + /// Returns the last modification time. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_mtime()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime(&self) -> i64; + /// Returns the last modification time, nano seconds part. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_mtime_nsec()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime_nsec(&self) -> i64; + /// Returns the last status change time. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_ctime()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime(&self) -> i64; + /// Returns the last status change time, nano seconds part. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_ctime_nsec()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime_nsec(&self) -> i64; + /// Returns the "preferred" blocksize for efficient filesystem I/O. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_blksize()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_blksize(&self) -> u64; + /// Returns the number of blocks allocated to the file, 512-byte units. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_blocks()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_blocks(&self) -> u64; +} + +#[stable(feature = "metadata_ext", since = "1.1.0")] +impl MetadataExt for Metadata { + #[allow(deprecated)] + fn as_raw_stat(&self) -> &raw::stat { + unsafe { + &*(self.as_inner().as_inner() as *const libc::stat64 + as *const raw::stat) + } + } + fn st_dev(&self) -> u64 { + self.as_inner().as_inner().st_dev as u64 + } + fn st_ino(&self) -> u64 { + self.as_inner().as_inner().st_ino as u64 + } + fn st_mode(&self) -> u32 { + self.as_inner().as_inner().st_mode as u32 + } + fn st_nlink(&self) -> u64 { + self.as_inner().as_inner().st_nlink as u64 + } + fn st_uid(&self) -> u32 { + self.as_inner().as_inner().st_uid as u32 + } + fn st_gid(&self) -> u32 { + self.as_inner().as_inner().st_gid as u32 + } + fn st_rdev(&self) -> u64 { + self.as_inner().as_inner().st_rdev as u64 + } + fn st_size(&self) -> u64 { + self.as_inner().as_inner().st_size as u64 + } + fn st_atime(&self) -> i64 { + self.as_inner().as_inner().st_atime as i64 + } + fn st_atime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_atime_nsec as i64 + } + fn st_mtime(&self) -> i64 { + self.as_inner().as_inner().st_mtime as i64 + } + fn st_mtime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_mtime_nsec as i64 + } + fn st_ctime(&self) -> i64 { + self.as_inner().as_inner().st_ctime as i64 + } + fn st_ctime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_ctime_nsec as i64 + } + fn st_blksize(&self) -> u64 { + self.as_inner().as_inner().st_blksize as u64 + } + fn st_blocks(&self) -> u64 { + self.as_inner().as_inner().st_blocks as u64 + } +} diff --git a/ctr-std/src/os/hermit/mod.rs b/ctr-std/src/os/hermit/mod.rs new file mode 100644 index 0000000..fcb22cd --- /dev/null +++ b/ctr-std/src/os/hermit/mod.rs @@ -0,0 +1,16 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! HermitCore-specific definitions + +#![stable(feature = "raw_ext", since = "1.1.0")] + +pub mod raw; +pub mod fs; diff --git a/ctr-std/src/os/hermit/raw.rs b/ctr-std/src/os/hermit/raw.rs new file mode 100644 index 0000000..282afe0 --- /dev/null +++ b/ctr-std/src/os/hermit/raw.rs @@ -0,0 +1,27 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! HermitCore-specific raw type definitions + +#![stable(feature = "raw_ext", since = "1.1.0")] +#![rustc_deprecated(since = "1.8.0", + reason = "these type aliases are no longer supported by \ + the standard library, the `libc` crate on \ + crates.io should be used instead for the correct \ + definitions")] +#![allow(deprecated)] +#![allow(missing_debug_implementations)] + +#[stable(feature = "pthread_t", since = "1.8.0")] +pub use libc::pthread_t; + +#[doc(inline)] +#[stable(feature = "raw_ext", since = "1.1.0")] +pub use libc::{dev_t, mode_t, off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t}; diff --git a/ctr-std/src/os/mod.rs b/ctr-std/src/os/mod.rs index 0bf1b0d..ff4dd4f 100644 --- a/ctr-std/src/os/mod.rs +++ b/ctr-std/src/os/mod.rs @@ -47,6 +47,7 @@ cfg_if! { #[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(target_os = "horizon")] pub mod horizon; #[cfg(any(target_os = "redox", unix))] diff --git a/ctr-std/src/os/raw/mod.rs b/ctr-std/src/os/raw/mod.rs index d5eeb52..dc33747 100644 --- a/ctr-std/src/os/raw/mod.rs +++ b/ctr-std/src/os/raw/mod.rs @@ -29,6 +29,9 @@ use fmt; all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")), all(target_os = "l4re", target_arch = "x86_64"), + all(target_os = "netbsd", any(target_arch = "aarch64", + target_arch = "arm", + target_arch = "powerpc")), all(target_os = "openbsd", target_arch = "aarch64"), all(target_os = "fuchsia", target_arch = "aarch64")))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8; @@ -41,6 +44,9 @@ use fmt; all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")), all(target_os = "l4re", target_arch = "x86_64"), + all(target_os = "netbsd", any(target_arch = "aarch64", + target_arch = "arm", + target_arch = "powerpc")), all(target_os = "openbsd", target_arch = "aarch64"), all(target_os = "fuchsia", target_arch = "aarch64"))))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = i8; diff --git a/ctr-std/src/panic.rs b/ctr-std/src/panic.rs index 229034e..b8c1c4f 100644 --- a/ctr-std/src/panic.rs +++ b/ctr-std/src/panic.rs @@ -15,11 +15,14 @@ use any::Any; use cell::UnsafeCell; use fmt; +use future::Future; +use mem::PinMut; use ops::{Deref, DerefMut}; use panicking; use ptr::{Unique, NonNull}; use rc::Rc; use sync::{Arc, Mutex, RwLock, atomic}; +use task::{self, Poll}; use thread::Result; #[stable(feature = "panic_hooks", since = "1.10.0")] @@ -107,8 +110,10 @@ pub use core::panic::{PanicInfo, Location}; /// /// [`AssertUnwindSafe`]: ./struct.AssertUnwindSafe.html #[stable(feature = "catch_unwind", since = "1.9.0")] -#[rustc_on_unimplemented = "the type {Self} may not be safely transferred \ - across an unwind boundary"] +#[rustc_on_unimplemented( + message="the type `{Self}` may not be safely transferred across an unwind boundary", + label="`{Self}` may not be safely transferred across an unwind boundary", +)] pub auto trait UnwindSafe {} /// A marker trait representing types where a shared reference is considered @@ -123,9 +128,12 @@ pub auto trait UnwindSafe {} /// [`UnsafeCell`]: ../cell/struct.UnsafeCell.html /// [`UnwindSafe`]: ./trait.UnwindSafe.html #[stable(feature = "catch_unwind", since = "1.9.0")] -#[rustc_on_unimplemented = "the type {Self} may contain interior mutability \ - and a reference may not be safely transferrable \ - across a catch_unwind boundary"] +#[rustc_on_unimplemented( + message="the type `{Self}` may contain interior mutability and a reference may not be safely \ + transferrable across a catch_unwind boundary", + label="`{Self}` may contain interior mutability and a reference may not be safely \ + transferrable across a catch_unwind boundary", +)] pub auto trait RefUnwindSafe {} /// A simple wrapper around a type to assert that it is unwind safe. @@ -315,6 +323,16 @@ impl fmt::Debug for AssertUnwindSafe { } } +#[unstable(feature = "futures_api", issue = "50547")] +impl<'a, F: Future> Future for AssertUnwindSafe { + type Output = F::Output; + + fn poll(self: PinMut, cx: &mut task::Context) -> Poll { + let pinned_field = unsafe { PinMut::map_unchecked(self, |x| &mut x.0) }; + pinned_field.poll(cx) + } +} + /// Invokes a closure, capturing the cause of an unwinding panic if one occurs. /// /// This function will return `Ok` with the closure's result if the closure @@ -403,6 +421,6 @@ pub fn catch_unwind R + UnwindSafe, R>(f: F) -> Result { /// } /// ``` #[stable(feature = "resume_unwind", since = "1.9.0")] -pub fn resume_unwind(payload: Box) -> ! { +pub fn resume_unwind(payload: Box) -> ! { panicking::update_count_then_panic(payload) } diff --git a/ctr-std/src/panicking.rs b/ctr-std/src/panicking.rs index 321d634..4cdde2b 100644 --- a/ctr-std/src/panicking.rs +++ b/ctr-std/src/panicking.rs @@ -36,7 +36,7 @@ use sys_common::util; use thread; thread_local! { - pub static LOCAL_STDERR: RefCell>> = { + pub static LOCAL_STDERR: RefCell>> = { RefCell::new(None) } } @@ -64,7 +64,7 @@ extern { #[derive(Copy, Clone)] enum Hook { Default, - Custom(*mut (Fn(&PanicInfo) + 'static + Sync + Send)), + Custom(*mut (dyn Fn(&PanicInfo) + 'static + Sync + Send)), } static HOOK_LOCK: RWLock = RWLock::new(); @@ -104,7 +104,7 @@ static mut HOOK: Hook = Hook::Default; /// panic!("Normal panic"); /// ``` #[stable(feature = "panic_hooks", since = "1.10.0")] -pub fn set_hook(hook: Box) { +pub fn set_hook(hook: Box) { if thread::panicking() { panic!("cannot modify the panic hook from a panicking thread"); } @@ -149,7 +149,7 @@ pub fn set_hook(hook: Box) { /// panic!("Normal panic"); /// ``` #[stable(feature = "panic_hooks", since = "1.10.0")] -pub fn take_hook() -> Box { +pub fn take_hook() -> Box { if thread::panicking() { panic!("cannot modify the panic hook from a panicking thread"); } @@ -222,7 +222,7 @@ fn default_hook(info: &PanicInfo) { consoleDebugInit(debugDevice_SVC); } - let write = |err: &mut ::io::Write| { + let write = |err: &mut dyn (::io::Write)| { let _ = writeln!(err, "thread '{}' panicked at '{}', {}", name, msg, location); @@ -273,7 +273,7 @@ pub fn update_panic_count(amt: isize) -> usize { pub use realstd::rt::update_panic_count; /// Invoke a closure, capturing the cause of an unwinding panic if one occurs. -pub unsafe fn try R>(f: F) -> Result> { +pub unsafe fn try R>(f: F) -> Result> { #[allow(unions_with_drop_fields)] union Data { f: F, @@ -344,18 +344,6 @@ pub fn panicking() -> bool { /// Entry point of panic from the libcore crate. #[cfg(not(test))] -#[cfg(stage0)] -#[lang = "panic_fmt"] -pub extern fn rust_begin_panic(msg: fmt::Arguments, - file: &'static str, - line: u32, - col: u32) -> ! { - begin_panic_fmt(&msg, &(file, line, col)) -} - -/// Entry point of panic from the libcore crate. -#[cfg(not(test))] -#[cfg(not(stage0))] #[panic_implementation] #[unwind(allowed)] pub fn rust_begin_panic(info: &PanicInfo) -> ! { @@ -368,78 +356,54 @@ pub fn rust_begin_panic(info: &PanicInfo) -> ! { /// site as much as possible (so that `panic!()` has as low an impact /// on (e.g.) the inlining of other functions as possible), by moving /// the actual formatting into this shared place. -#[cfg(stage0)] #[unstable(feature = "libstd_sys_internals", reason = "used by the panic! macro", issue = "0")] #[inline(never)] #[cold] pub fn begin_panic_fmt(msg: &fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! { - // We do two allocations here, unfortunately. But (a) they're - // required with the current scheme, and (b) we don't handle - // panic + OOM properly anyway (see comment in begin_panic - // below). - - rust_panic_with_hook(&mut PanicPayload::new(msg), Some(msg), file_line_col); -} - -// NOTE(stage0) move into `continue_panic_fmt` on next stage0 update -struct PanicPayload<'a> { - inner: &'a fmt::Arguments<'a>, - string: Option, + let (file, line, col) = *file_line_col; + let info = PanicInfo::internal_constructor( + Some(msg), + Location::internal_constructor(file, line, col), + ); + continue_panic_fmt(&info) } -impl<'a> PanicPayload<'a> { - fn new(inner: &'a fmt::Arguments<'a>) -> PanicPayload<'a> { - PanicPayload { inner, string: None } +fn continue_panic_fmt(info: &PanicInfo) -> ! { + struct PanicPayload<'a> { + inner: &'a fmt::Arguments<'a>, + string: Option, } - fn fill(&mut self) -> &mut String { - use fmt::Write; + impl<'a> PanicPayload<'a> { + fn new(inner: &'a fmt::Arguments<'a>) -> PanicPayload<'a> { + PanicPayload { inner, string: None } + } - let inner = self.inner; - self.string.get_or_insert_with(|| { - let mut s = String::new(); - drop(s.write_fmt(*inner)); - s - }) - } -} + fn fill(&mut self) -> &mut String { + use fmt::Write; -unsafe impl<'a> BoxMeUp for PanicPayload<'a> { - fn box_me_up(&mut self) -> *mut (Any + Send) { - let contents = mem::replace(self.fill(), String::new()); - Box::into_raw(Box::new(contents)) + let inner = self.inner; + self.string.get_or_insert_with(|| { + let mut s = String::new(); + drop(s.write_fmt(*inner)); + s + }) + } } - fn get(&mut self) -> &(Any + Send) { - self.fill() - } -} + unsafe impl<'a> BoxMeUp for PanicPayload<'a> { + fn box_me_up(&mut self) -> *mut (dyn Any + Send) { + let contents = mem::replace(self.fill(), String::new()); + Box::into_raw(Box::new(contents)) + } -/// The entry point for panicking with a formatted message. -/// -/// This is designed to reduce the amount of code required at the call -/// site as much as possible (so that `panic!()` has as low an impact -/// on (e.g.) the inlining of other functions as possible), by moving -/// the actual formatting into this shared place. -#[cfg(not(stage0))] -#[unstable(feature = "libstd_sys_internals", - reason = "used by the panic! macro", - issue = "0")] -#[inline(never)] #[cold] -pub fn begin_panic_fmt(msg: &fmt::Arguments, - file_line_col: &(&'static str, u32, u32)) -> ! { - let (file, line, col) = *file_line_col; - let info = PanicInfo::internal_constructor( - Some(msg), - Location::internal_constructor(file, line, col), - ); - continue_panic_fmt(&info) -} + fn get(&mut self) -> &(dyn Any + Send) { + self.fill() + } + } -#[cfg(not(stage0))] -fn continue_panic_fmt(info: &PanicInfo) -> ! { // We do two allocations here, unfortunately. But (a) they're // required with the current scheme, and (b) we don't handle // panic + OOM properly anyway (see comment in begin_panic @@ -480,15 +444,15 @@ pub fn begin_panic(msg: M, file_line_col: &(&'static str, u32, u3 } unsafe impl BoxMeUp for PanicPayload { - fn box_me_up(&mut self) -> *mut (Any + Send) { + fn box_me_up(&mut self) -> *mut (dyn Any + Send) { let data = match self.inner.take() { - Some(a) => Box::new(a) as Box, + Some(a) => Box::new(a) as Box, None => Box::new(()), }; Box::into_raw(data) } - fn get(&mut self) -> &(Any + Send) { + fn get(&mut self) -> &(dyn Any + Send) { match self.inner { Some(ref a) => a, None => &(), @@ -502,7 +466,7 @@ pub fn begin_panic(msg: M, file_line_col: &(&'static str, u32, u3 /// Executes the primary logic for a panic, including checking for recursive /// panics, panic hooks, and finally dispatching to the panic runtime to either /// abort or unwind. -fn rust_panic_with_hook(payload: &mut BoxMeUp, +fn rust_panic_with_hook(payload: &mut dyn BoxMeUp, message: Option<&fmt::Arguments>, file_line_col: &(&str, u32, u32)) -> ! { let (file, line, col) = *file_line_col; @@ -557,17 +521,17 @@ fn rust_panic_with_hook(payload: &mut BoxMeUp, } /// Shim around rust_panic. Called by resume_unwind. -pub fn update_count_then_panic(msg: Box) -> ! { +pub fn update_count_then_panic(msg: Box) -> ! { update_panic_count(1); - struct RewrapBox(Box); + struct RewrapBox(Box); unsafe impl BoxMeUp for RewrapBox { - fn box_me_up(&mut self) -> *mut (Any + Send) { + fn box_me_up(&mut self) -> *mut (dyn Any + Send) { Box::into_raw(mem::replace(&mut self.0, Box::new(()))) } - fn get(&mut self) -> &(Any + Send) { + fn get(&mut self) -> &(dyn Any + Send) { &*self.0 } } @@ -578,9 +542,9 @@ pub fn update_count_then_panic(msg: Box) -> ! { /// A private no-mangle function on which to slap yer breakpoints. #[no_mangle] #[allow(private_no_mangle_fns)] // yes we get it, but we like breakpoints -pub fn rust_panic(mut msg: &mut BoxMeUp) -> ! { +pub fn rust_panic(mut msg: &mut dyn BoxMeUp) -> ! { let code = unsafe { - let obj = &mut msg as *mut &mut BoxMeUp; + let obj = &mut msg as *mut &mut dyn BoxMeUp; __rust_start_panic(obj as usize) }; rtabort!("failed to initiate panic, error {}", code) diff --git a/ctr-std/src/path.rs b/ctr-std/src/path.rs index 27f57bd..ae7b632 100644 --- a/ctr-std/src/path.rs +++ b/ctr-std/src/path.rs @@ -1045,8 +1045,6 @@ impl<'a> cmp::Ord for Components<'a> { /// # Examples /// /// ``` -/// #![feature(path_ancestors)] -/// /// use std::path::Path; /// /// let path = Path::new("/foo/bar"); @@ -1059,26 +1057,23 @@ impl<'a> cmp::Ord for Components<'a> { /// [`ancestors`]: struct.Path.html#method.ancestors /// [`Path`]: struct.Path.html #[derive(Copy, Clone, Debug)] -#[unstable(feature = "path_ancestors", issue = "48581")] +#[stable(feature = "path_ancestors", since = "1.28.0")] pub struct Ancestors<'a> { next: Option<&'a Path>, } -#[unstable(feature = "path_ancestors", issue = "48581")] +#[stable(feature = "path_ancestors", since = "1.28.0")] impl<'a> Iterator for Ancestors<'a> { type Item = &'a Path; fn next(&mut self) -> Option { let next = self.next; - self.next = match next { - Some(path) => path.parent(), - None => None, - }; + self.next = next.and_then(Path::parent); next } } -#[unstable(feature = "path_ancestors", issue = "48581")] +#[stable(feature = "path_ancestors", since = "1.28.0")] impl<'a> FusedIterator for Ancestors<'a> {} //////////////////////////////////////////////////////////////////////////////// @@ -1415,6 +1410,14 @@ impl From for Box { } } +#[stable(feature = "more_box_slice_clone", since = "1.29.0")] +impl Clone for Box { + #[inline] + fn clone(&self) -> Self { + self.to_path_buf().into_boxed_path() + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T: ?Sized + AsRef> From<&'a T> for PathBuf { fn from(s: &'a T) -> PathBuf { @@ -1737,9 +1740,11 @@ impl Path { /// Converts a `Path` to a [`Cow`]. /// - /// Any non-Unicode sequences are replaced with U+FFFD REPLACEMENT CHARACTER. + /// Any non-Unicode sequences are replaced with + /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD]. /// /// [`Cow`]: ../borrow/enum.Cow.html + /// [U+FFFD]: ../char/constant.REPLACEMENT_CHARACTER.html /// /// # Examples /// @@ -1833,7 +1838,7 @@ impl Path { /// * On Unix, a path has a root if it begins with `/`. /// /// * On Windows, a path has a root if it: - /// * has no prefix and begins with a separator, e.g. `\\windows` + /// * has no prefix and begins with a separator, e.g. `\windows` /// * has a prefix followed by a separator, e.g. `c:\windows` but not `c:windows` /// * has any non-disk prefix, e.g. `\\server\share` /// @@ -1893,8 +1898,6 @@ impl Path { /// # Examples /// /// ``` - /// #![feature(path_ancestors)] - /// /// use std::path::Path; /// /// let mut ancestors = Path::new("/foo/bar").ancestors(); @@ -1906,7 +1909,7 @@ impl Path { /// /// [`None`]: ../../std/option/enum.Option.html#variant.None /// [`parent`]: struct.Path.html#method.parent - #[unstable(feature = "path_ancestors", issue = "48581")] + #[stable(feature = "path_ancestors", since = "1.28.0")] pub fn ancestors(&self) -> Ancestors { Ancestors { next: Some(&self), diff --git a/ctr-std/src/prelude/v1.rs b/ctr-std/src/prelude/v1.rs index feedd4e..53763da 100644 --- a/ctr-std/src/prelude/v1.rs +++ b/ctr-std/src/prelude/v1.rs @@ -12,42 +12,68 @@ //! //! See the [module-level documentation](../index.html) for more. + + #![stable(feature = "rust1", since = "1.0.0")] // Re-exported core operators #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use marker::{Copy, Send, Sized, Sync}; +#[doc(no_inline)] +pub use marker::{Copy, Send, Sized, Sync}; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use ops::{Drop, Fn, FnMut, FnOnce}; +#[doc(no_inline)] +pub use ops::{Drop, Fn, FnMut, FnOnce}; // Re-exported functions #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use mem::drop; +#[doc(no_inline)] +pub use mem::drop; // Re-exported types and traits #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use boxed::Box; +#[doc(no_inline)] +pub use clone::Clone; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use borrow::ToOwned; +#[doc(no_inline)] +pub use cmp::{PartialEq, PartialOrd, Eq, Ord}; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use clone::Clone; +#[doc(no_inline)] +pub use convert::{AsRef, AsMut, Into, From}; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use cmp::{PartialEq, PartialOrd, Eq, Ord}; +#[doc(no_inline)] +pub use default::Default; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use convert::{AsRef, AsMut, Into, From}; +#[doc(no_inline)] +pub use iter::{Iterator, Extend, IntoIterator}; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use default::Default; +#[doc(no_inline)] +pub use iter::{DoubleEndedIterator, ExactSizeIterator}; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use iter::{Iterator, Extend, IntoIterator}; +#[doc(no_inline)] +pub use option::Option::{self, Some, None}; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use iter::{DoubleEndedIterator, ExactSizeIterator}; +#[doc(no_inline)] +pub use result::Result::{self, Ok, Err}; + + +// The file so far is equivalent to src/libcore/prelude/v1.rs, +// and below to src/liballoc/prelude.rs. +// Those files are duplicated rather than using glob imports +// because we want docs to show these re-exports as pointing to within `std`. + + #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use option::Option::{self, Some, None}; +#[doc(no_inline)] +pub use boxed::Box; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use result::Result::{self, Ok, Err}; +#[doc(no_inline)] +pub use borrow::ToOwned; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use slice::SliceConcatExt; +#[doc(no_inline)] +pub use slice::SliceConcatExt; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use string::{String, ToString}; +#[doc(no_inline)] +pub use string::{String, ToString}; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use vec::Vec; +#[doc(no_inline)] +pub use vec::Vec; diff --git a/ctr-std/src/process.rs b/ctr-std/src/process.rs index 732f43c..9dd0767 100644 --- a/ctr-std/src/process.rs +++ b/ctr-std/src/process.rs @@ -381,6 +381,39 @@ impl fmt::Debug for ChildStderr { /// /// let hello = output.stdout; /// ``` +/// +/// `Command` can be reused to spawn multiple processes. The builder methods +/// change the command without needing to immediately spawn the process. +/// +/// ```no_run +/// use std::process::Command; +/// +/// let mut echo_hello = Command::new("sh"); +/// echo_hello.arg("-c") +/// .arg("echo hello"); +/// let hello_1 = echo_hello.output().expect("failed to execute process"); +/// let hello_2 = echo_hello.output().expect("failed to execute process"); +/// ``` +/// +/// Similarly, you can call builder methods after spawning a process and then +/// spawn a new process with the modified settings. +/// +/// ```no_run +/// use std::process::Command; +/// +/// let mut list_dir = Command::new("ls"); +/// +/// // Execute `ls` in the current directory of the program. +/// list_dir.status().expect("process failed to execute"); +/// +/// println!(""); +/// +/// // Change `ls` to execute in the root directory. +/// list_dir.current_dir("/"); +/// +/// // And then execute `ls` again but in the root directory. +/// list_dir.status().expect("process failed to execute"); +/// ``` #[stable(feature = "process", since = "1.0.0")] pub struct Command { inner: imp::Command, @@ -813,13 +846,13 @@ impl fmt::Debug for Output { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let stdout_utf8 = str::from_utf8(&self.stdout); - let stdout_debug: &fmt::Debug = match stdout_utf8 { + let stdout_debug: &dyn fmt::Debug = match stdout_utf8 { Ok(ref str) => str, Err(_) => &self.stdout }; let stderr_utf8 = str::from_utf8(&self.stderr); - let stderr_debug: &fmt::Debug = match stderr_utf8 { + let stderr_debug: &dyn fmt::Debug = match stderr_utf8 { Ok(ref str) => str, Err(_) => &self.stderr }; diff --git a/ctr-std/src/rt.rs b/ctr-std/src/rt.rs index e139276..fdaf2a8 100644 --- a/ctr-std/src/rt.rs +++ b/ctr-std/src/rt.rs @@ -29,7 +29,7 @@ pub use panicking::{begin_panic, begin_panic_fmt, update_panic_count}; // To reduce the generated code of the new `lang_start`, this function is doing // the real work. #[cfg(not(test))] -fn lang_start_internal(main: &(Fn() -> i32 + Sync + ::panic::RefUnwindSafe), +fn lang_start_internal(main: &(dyn Fn() -> i32 + Sync + ::panic::RefUnwindSafe), argc: isize, argv: *const *const u8) -> isize { use panic; use sys; diff --git a/ctr-std/src/sync/mod.rs b/ctr-std/src/sync/mod.rs index 642b284..e12ef8d 100644 --- a/ctr-std/src/sync/mod.rs +++ b/ctr-std/src/sync/mod.rs @@ -18,7 +18,7 @@ #![stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc_crate::arc::{Arc, Weak}; +pub use alloc_crate::sync::{Arc, Weak}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::sync::atomic; diff --git a/ctr-std/src/sync/mpsc/mod.rs b/ctr-std/src/sync/mpsc/mod.rs index 2dd3aeb..59cf741 100644 --- a/ctr-std/src/sync/mpsc/mod.rs +++ b/ctr-std/src/sync/mpsc/mod.rs @@ -689,7 +689,7 @@ impl UnsafeFlavor for Receiver { /// only one [`Receiver`] is supported. /// /// If the [`Receiver`] is disconnected while trying to [`send`] with the -/// [`Sender`], the [`send`] method will return a [`SendError`]. Similarly, If the +/// [`Sender`], the [`send`] method will return a [`SendError`]. Similarly, if the /// [`Sender`] is disconnected while trying to [`recv`], the [`recv`] method will /// return a [`RecvError`]. /// @@ -1247,6 +1247,34 @@ impl Receiver { /// [`SyncSender`]: struct.SyncSender.html /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err /// + /// # Known Issues + /// + /// There is currently a known issue (see [`#39364`]) that causes `recv_timeout` + /// to panic unexpectedly with the following example: + /// + /// ```no_run + /// use std::sync::mpsc::channel; + /// use std::thread; + /// use std::time::Duration; + /// + /// let (tx, rx) = channel::(); + /// + /// thread::spawn(move || { + /// let d = Duration::from_millis(10); + /// loop { + /// println!("recv"); + /// let _r = rx.recv_timeout(d); + /// } + /// }); + /// + /// thread::sleep(Duration::from_millis(100)); + /// let _c1 = tx.clone(); + /// + /// thread::sleep(Duration::from_secs(1)); + /// ``` + /// + /// [`#39364`]: https://github.com/rust-lang/rust/issues/39364 + /// /// # Examples /// /// Successfully receiving value before encountering timeout: @@ -1638,7 +1666,7 @@ impl error::Error for SendError { "sending on a closed channel" } - fn cause(&self) -> Option<&error::Error> { + fn cause(&self) -> Option<&dyn error::Error> { None } } @@ -1681,7 +1709,7 @@ impl error::Error for TrySendError { } } - fn cause(&self) -> Option<&error::Error> { + fn cause(&self) -> Option<&dyn error::Error> { None } } @@ -1709,7 +1737,7 @@ impl error::Error for RecvError { "receiving on a closed channel" } - fn cause(&self) -> Option<&error::Error> { + fn cause(&self) -> Option<&dyn error::Error> { None } } @@ -1742,7 +1770,7 @@ impl error::Error for TryRecvError { } } - fn cause(&self) -> Option<&error::Error> { + fn cause(&self) -> Option<&dyn error::Error> { None } } @@ -1783,7 +1811,7 @@ impl error::Error for RecvTimeoutError { } } - fn cause(&self) -> Option<&error::Error> { + fn cause(&self) -> Option<&dyn error::Error> { None } } diff --git a/ctr-std/src/sync/mpsc/select.rs b/ctr-std/src/sync/mpsc/select.rs index 9310dad..a7a284c 100644 --- a/ctr-std/src/sync/mpsc/select.rs +++ b/ctr-std/src/sync/mpsc/select.rs @@ -93,7 +93,7 @@ pub struct Handle<'rx, T:Send+'rx> { next: *mut Handle<'static, ()>, prev: *mut Handle<'static, ()>, added: bool, - packet: &'rx (Packet+'rx), + packet: &'rx (dyn Packet+'rx), // due to our fun transmutes, we be sure to place this at the end. (nothing // previous relies on T) diff --git a/ctr-std/src/sync/mutex.rs b/ctr-std/src/sync/mutex.rs index f3503b0..e5a4106 100644 --- a/ctr-std/src/sync/mutex.rs +++ b/ctr-std/src/sync/mutex.rs @@ -227,7 +227,7 @@ impl Mutex { #[stable(feature = "rust1", since = "1.0.0")] pub fn lock(&self) -> LockResult> { unsafe { - self.inner.lock(); + self.inner.raw_lock(); MutexGuard::new(self) } } @@ -454,7 +454,7 @@ impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> { fn drop(&mut self) { unsafe { self.__lock.poison.done(&self.__poison); - self.__lock.inner.unlock(); + self.__lock.inner.raw_unlock(); } } } diff --git a/ctr-std/src/sync/once.rs b/ctr-std/src/sync/once.rs index 7eb7be2..f6cb8be 100644 --- a/ctr-std/src/sync/once.rs +++ b/ctr-std/src/sync/once.rs @@ -31,12 +31,10 @@ // initialization closure panics, the Once enters a "poisoned" state which means // that all future calls will immediately panic as well. // -// So to implement this, one might first reach for a `StaticMutex`, but those -// unfortunately need to be deallocated (e.g. call `destroy()`) to free memory -// on all OSes (some of the BSDs allocate memory for mutexes). It also gets a -// lot harder with poisoning to figure out when the mutex needs to be -// deallocated because it's not after the closure finishes, but after the first -// successful closure finishes. +// So to implement this, one might first reach for a `Mutex`, but those cannot +// be put into a `static`. It also gets a lot harder with poisoning to figure +// out when the mutex needs to be deallocated because it's not after the closure +// finishes, but after the first successful closure finishes. // // All in all, this is instead implemented with atomics and lock-free // operations! Whee! Each `Once` has one word of atomic state, and this state is @@ -149,9 +147,9 @@ struct Waiter { // Helper struct used to clean up after a closure call with a `Drop` // implementation to also run on panic. -struct Finish { +struct Finish<'a> { panicked: bool, - me: &'static Once, + me: &'a Once, } impl Once { @@ -178,6 +176,10 @@ impl Once { /// happens-before relation between the closure and code executing after the /// return). /// + /// If the given closure recusively invokes `call_once` on the same `Once` + /// instance the exact behavior is not specified, allowed outcomes are + /// a panic or a deadlock. + /// /// # Examples /// /// ``` @@ -218,9 +220,13 @@ impl Once { /// /// [poison]: struct.Mutex.html#poisoning #[stable(feature = "rust1", since = "1.0.0")] - pub fn call_once(&'static self, f: F) where F: FnOnce() { + pub fn call_once(&self, f: F) where F: FnOnce() { // Fast path, just see if we've completed initialization. - if self.state.load(Ordering::SeqCst) == COMPLETE { + // An `Acquire` load is enough because that makes all the initialization + // operations visible to us. The cold path uses SeqCst consistently + // because the performance difference really does not matter there, + // and SeqCst minimizes the chances of something going wrong. + if self.state.load(Ordering::Acquire) == COMPLETE { return } @@ -275,9 +281,13 @@ impl Once { /// INIT.call_once(|| {}); /// ``` #[unstable(feature = "once_poison", issue = "33577")] - pub fn call_once_force(&'static self, f: F) where F: FnOnce(&OnceState) { + pub fn call_once_force(&self, f: F) where F: FnOnce(&OnceState) { // same as above, just with a different parameter to `call_inner`. - if self.state.load(Ordering::SeqCst) == COMPLETE { + // An `Acquire` load is enough because that makes all the initialization + // operations visible to us. The cold path uses SeqCst consistently + // because the performance difference really does not matter there, + // and SeqCst minimizes the chances of something going wrong. + if self.state.load(Ordering::Acquire) == COMPLETE { return } @@ -299,9 +309,9 @@ impl Once { // currently no way to take an `FnOnce` and call it via virtual dispatch // without some allocation overhead. #[cold] - fn call_inner(&'static self, + fn call_inner(&self, ignore_poisoning: bool, - init: &mut FnMut(bool)) { + init: &mut dyn FnMut(bool)) { let mut state = self.state.load(Ordering::SeqCst); 'outer: loop { @@ -390,7 +400,7 @@ impl fmt::Debug for Once { } } -impl Drop for Finish { +impl<'a> Drop for Finish<'a> { fn drop(&mut self) { // Swap out our state with however we finished. We should only ever see // an old state which was RUNNING. diff --git a/ctr-std/src/sys/cloudabi/abi/cloudabi.rs b/ctr-std/src/sys/cloudabi/abi/cloudabi.rs index 2909db5..cd9a5ad 100644 --- a/ctr-std/src/sys/cloudabi/abi/cloudabi.rs +++ b/ctr-std/src/sys/cloudabi/abi/cloudabi.rs @@ -121,6 +121,7 @@ include!("bitflags.rs"); /// File or memory access pattern advisory information. #[repr(u8)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +#[non_exhaustive] pub enum advice { /// The application expects that it will not access the /// specified data in the near future. @@ -140,12 +141,12 @@ pub enum advice { /// The application expects to access the specified data /// in the near future. WILLNEED = 6, - #[doc(hidden)] _NonExhaustive = -1 as isize as u8, } /// Enumeration describing the kind of value stored in [`auxv`](struct.auxv.html). #[repr(u32)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +#[non_exhaustive] pub enum auxtype { /// Base address of the binary argument data provided to /// [`proc_exec()`](fn.proc_exec.html). @@ -210,12 +211,12 @@ pub enum auxtype { SYSINFO_EHDR = 262, /// Thread ID of the initial thread of the process. TID = 261, - #[doc(hidden)] _NonExhaustive = -1 as isize as u32, } /// Identifiers for clocks. #[repr(u32)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +#[non_exhaustive] pub enum clockid { /// The system-wide monotonic clock, which is defined as a /// clock measuring real time, whose value cannot be @@ -232,7 +233,6 @@ pub enum clockid { REALTIME = 3, /// The CPU-time clock associated with the current thread. THREAD_CPUTIME_ID = 4, - #[doc(hidden)] _NonExhaustive = -1 as isize as u32, } /// A userspace condition variable. @@ -267,6 +267,7 @@ pub const DIRCOOKIE_START: dircookie = dircookie(0); /// exclusively or merely provided for alignment with POSIX. #[repr(u16)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +#[non_exhaustive] pub enum errno { /// No error occurred. System call completed successfully. SUCCESS = 0, @@ -422,7 +423,6 @@ pub enum errno { XDEV = 75, /// Extension: Capabilities insufficient. NOTCAPABLE = 76, - #[doc(hidden)] _NonExhaustive = -1 as isize as u16, } bitflags! { @@ -438,6 +438,7 @@ bitflags! { /// Type of a subscription to an event or its occurrence. #[repr(u8)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +#[non_exhaustive] pub enum eventtype { /// The time value of clock [`subscription.union.clock.clock_id`](struct.subscription_clock.html#structfield.clock_id) /// has reached timestamp [`subscription.union.clock.timeout`](struct.subscription_clock.html#structfield.timeout). @@ -463,7 +464,6 @@ pub enum eventtype { /// The process associated with process descriptor /// [`subscription.union.proc_terminate.fd`](struct.subscription_proc_terminate.html#structfield.fd) has terminated. PROC_TERMINATE = 7, - #[doc(hidden)] _NonExhaustive = -1 as isize as u8, } /// Exit code generated by a process when exiting. @@ -530,6 +530,7 @@ pub type filesize = u64; /// The type of a file descriptor or file. #[repr(u8)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +#[non_exhaustive] pub enum filetype { /// The type of the file descriptor or file is unknown or /// is different from any of the other types specified. @@ -558,7 +559,6 @@ pub enum filetype { SOCKET_STREAM = 130, /// The file refers to a symbolic link inode. SYMBOLIC_LINK = 144, - #[doc(hidden)] _NonExhaustive = -1 as isize as u8, } bitflags! { @@ -847,12 +847,12 @@ bitflags! { /// memory. #[repr(u8)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +#[non_exhaustive] pub enum scope { /// The object is stored in private memory. PRIVATE = 4, /// The object is stored in shared memory. SHARED = 8, - #[doc(hidden)] _NonExhaustive = -1 as isize as u8, } bitflags! { @@ -878,6 +878,7 @@ bitflags! { /// Signal condition. #[repr(u8)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +#[non_exhaustive] pub enum signal { /// Process abort signal. /// @@ -983,7 +984,6 @@ pub enum signal { /// /// Action: Terminates the process. XFSZ = 26, - #[doc(hidden)] _NonExhaustive = -1 as isize as u8, } bitflags! { @@ -1049,6 +1049,7 @@ pub type userdata = u64; /// should be set. #[repr(u8)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +#[non_exhaustive] pub enum whence { /// Seek relative to current position. CUR = 1, @@ -1056,7 +1057,6 @@ pub enum whence { END = 2, /// Seek relative to start-of-file. SET = 3, - #[doc(hidden)] _NonExhaustive = -1 as isize as u8, } /// Auxiliary vector entry. diff --git a/ctr-std/src/sys/cloudabi/backtrace.rs b/ctr-std/src/sys/cloudabi/backtrace.rs index 1b97018..2c43b59 100644 --- a/ctr-std/src/sys/cloudabi/backtrace.rs +++ b/ctr-std/src/sys/cloudabi/backtrace.rs @@ -64,6 +64,10 @@ extern "C" fn trace_fn( arg: *mut libc::c_void, ) -> uw::_Unwind_Reason_Code { let cx = unsafe { &mut *(arg as *mut Context) }; + if cx.idx >= cx.frames.len() { + return uw::_URC_NORMAL_STOP; + } + let mut ip_before_insn = 0; let mut ip = unsafe { uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void }; if !ip.is_null() && ip_before_insn == 0 { @@ -73,14 +77,12 @@ extern "C" fn trace_fn( } let symaddr = unsafe { uw::_Unwind_FindEnclosingFunction(ip) }; - if cx.idx < cx.frames.len() { - cx.frames[cx.idx] = Frame { - symbol_addr: symaddr as *mut u8, - exact_position: ip as *mut u8, - inline_context: 0, - }; - cx.idx += 1; - } + cx.frames[cx.idx] = Frame { + symbol_addr: symaddr as *mut u8, + exact_position: ip as *mut u8, + inline_context: 0, + }; + cx.idx += 1; uw::_URC_NO_REASON } diff --git a/ctr-std/src/sys/cloudabi/thread.rs b/ctr-std/src/sys/cloudabi/thread.rs index 5d66936..8cca47e 100644 --- a/ctr-std/src/sys/cloudabi/thread.rs +++ b/ctr-std/src/sys/cloudabi/thread.rs @@ -32,7 +32,7 @@ unsafe impl Send for Thread {} unsafe impl Sync for Thread {} impl Thread { - pub unsafe fn new<'a>(stack: usize, p: Box) -> io::Result { + pub unsafe fn new<'a>(stack: usize, p: Box) -> io::Result { let p = box p; let mut native: libc::pthread_t = mem::zeroed(); let mut attr: libc::pthread_attr_t = mem::zeroed(); diff --git a/ctr-std/src/sys/horizon/net.rs b/ctr-std/src/sys/horizon/net.rs index b6af433..14c58eb 100644 --- a/ctr-std/src/sys/horizon/net.rs +++ b/ctr-std/src/sys/horizon/net.rs @@ -148,7 +148,9 @@ impl Socket { let mut pollfd = libc::pollfd { fd: self.0.raw(), - events: libc::POLLOUT, + // supposed to be `libc::POLLOUT`, but the value in the `libc` crate is currently + // incorrect for the 3DS + events: 0x10, revents: 0, }; @@ -184,9 +186,9 @@ impl Socket { } 0 => {} _ => { - // linux returns POLLOUT|POLLERR|POLLHUP for refused connections (!), so look - // for POLLHUP rather than read readiness - if pollfd.revents & libc::POLLHUP != 0 { + // `libc::POLLHUP` should be 0x4, but the constant is currently defined + // incorrectly for 3DS. So we just specifiy it manually for now. + if pollfd.revents & 0x4 != 0 { let e = self.take_error()? .unwrap_or_else(|| { io::Error::new(io::ErrorKind::Other, "no error set after POLLHUP") @@ -343,8 +345,7 @@ impl Socket { } pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - let mut nonblocking = nonblocking as libc::c_int; - cvt(unsafe { libc::ioctl(*self.as_inner(), libc::FIONBIO as u32, &mut nonblocking) }).map(|_| ()) + self.0.set_nonblocking(nonblocking) } pub fn take_error(&self) -> io::Result> { diff --git a/ctr-std/src/sys/mod.rs b/ctr-std/src/sys/mod.rs index d0ed80e..9aa6662 100644 --- a/ctr-std/src/sys/mod.rs +++ b/ctr-std/src/sys/mod.rs @@ -70,6 +70,7 @@ cfg_if! { // (missing things in `libc` which is empty) so just omit everything // with an empty module #[unstable(issue = "0", feature = "std_internals")] + #[allow(missing_docs)] pub mod unix_ext {} } else { // On other platforms like Windows document the bare bones of unix @@ -83,11 +84,13 @@ cfg_if! { cfg_if! { if #[cfg(windows)] { // 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"))] { // On CloudABI and wasm right now the shim below doesn't compile, so // just omit it #[unstable(issue = "0", feature = "std_internals")] + #[allow(missing_docs)] pub mod windows_ext {} } else { // On all other platforms (aka linux/osx/etc) then pull in a "minimal" diff --git a/ctr-std/src/sys/redox/args.rs b/ctr-std/src/sys/redox/args.rs index 59ae2a7..556ed77 100644 --- a/ctr-std/src/sys/redox/args.rs +++ b/ctr-std/src/sys/redox/args.rs @@ -73,17 +73,15 @@ mod imp { CStr::from_ptr(*argv.offset(i) as *const libc::c_char).to_bytes().to_vec() }).collect(); - LOCK.lock(); + let _guard = LOCK.lock(); let ptr = get_global_ptr(); assert!((*ptr).is_none()); (*ptr) = Some(box args); - LOCK.unlock(); } pub unsafe fn cleanup() { - LOCK.lock(); + let _guard = LOCK.lock(); *get_global_ptr() = None; - LOCK.unlock(); } pub fn args() -> Args { @@ -96,16 +94,14 @@ mod imp { fn clone() -> Option>> { unsafe { - LOCK.lock(); + let _guard = LOCK.lock(); let ptr = get_global_ptr(); - let ret = (*ptr).as_ref().map(|s| (**s).clone()); - LOCK.unlock(); - return ret + (*ptr).as_ref().map(|s| (**s).clone()) } } - fn get_global_ptr() -> *mut Option>>> { - unsafe { mem::transmute(&GLOBAL_ARGS_PTR) } + unsafe fn get_global_ptr() -> *mut Option>>> { + mem::transmute(&GLOBAL_ARGS_PTR) } } diff --git a/ctr-std/src/sys/redox/backtrace/tracing.rs b/ctr-std/src/sys/redox/backtrace/tracing.rs index bb70ca3..c0414b7 100644 --- a/ctr-std/src/sys/redox/backtrace/tracing.rs +++ b/ctr-std/src/sys/redox/backtrace/tracing.rs @@ -68,6 +68,10 @@ pub fn unwind_backtrace(frames: &mut [Frame]) extern fn trace_fn(ctx: *mut uw::_Unwind_Context, arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code { let cx = unsafe { &mut *(arg as *mut Context) }; + if cx.idx >= cx.frames.len() { + return uw::_URC_NORMAL_STOP; + } + let mut ip_before_insn = 0; let mut ip = unsafe { uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void @@ -94,14 +98,12 @@ extern fn trace_fn(ctx: *mut uw::_Unwind_Context, unsafe { uw::_Unwind_FindEnclosingFunction(ip) } }; - if cx.idx < cx.frames.len() { - cx.frames[cx.idx] = Frame { - symbol_addr: symaddr as *mut u8, - exact_position: ip as *mut u8, - inline_context: 0, - }; - cx.idx += 1; - } + cx.frames[cx.idx] = Frame { + symbol_addr: symaddr as *mut u8, + exact_position: ip as *mut u8, + inline_context: 0, + }; + cx.idx += 1; uw::_URC_NO_REASON } diff --git a/ctr-std/src/sys/redox/ext/mod.rs b/ctr-std/src/sys/redox/ext/mod.rs index 9fd8d6c..cb2c75a 100644 --- a/ctr-std/src/sys/redox/ext/mod.rs +++ b/ctr-std/src/sys/redox/ext/mod.rs @@ -33,6 +33,7 @@ pub mod ffi; pub mod fs; pub mod io; +pub mod net; pub mod process; pub mod thread; diff --git a/ctr-std/src/sys/redox/ext/net.rs b/ctr-std/src/sys/redox/ext/net.rs new file mode 100644 index 0000000..2ab7770 --- /dev/null +++ b/ctr-std/src/sys/redox/ext/net.rs @@ -0,0 +1,769 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![stable(feature = "unix_socket_redox", since = "1.29")] + +//! Unix-specific networking functionality + +use fmt; +use io::{self, Error, ErrorKind, Initializer}; +use net::Shutdown; +use os::unix::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd}; +use path::Path; +use time::Duration; +use sys::{cvt, fd::FileDesc, syscall}; + +/// An address associated with a Unix socket. +/// +/// # Examples +/// +/// ``` +/// use std::os::unix::net::UnixListener; +/// +/// let socket = match UnixListener::bind("/tmp/sock") { +/// Ok(sock) => sock, +/// Err(e) => { +/// println!("Couldn't bind: {:?}", e); +/// return +/// } +/// }; +/// let addr = socket.local_addr().expect("Couldn't get local address"); +/// ``` +#[derive(Clone)] +#[stable(feature = "unix_socket_redox", since = "1.29")] +pub struct SocketAddr(()); + +impl SocketAddr { + /// Returns the contents of this address if it is a `pathname` address. + /// + /// # Examples + /// + /// With a pathname: + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// use std::path::Path; + /// + /// let socket = UnixListener::bind("/tmp/sock").unwrap(); + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock"))); + /// ``` + /// + /// Without a pathname: + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// + /// let socket = UnixDatagram::unbound().unwrap(); + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.as_pathname(), None); + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn as_pathname(&self) -> Option<&Path> { + None + } + + /// Returns true if and only if the address is unnamed. + /// + /// # Examples + /// + /// A named address: + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let socket = UnixListener::bind("/tmp/sock").unwrap(); + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.is_unnamed(), false); + /// ``` + /// + /// An unnamed address: + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// + /// let socket = UnixDatagram::unbound().unwrap(); + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.is_unnamed(), true); + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn is_unnamed(&self) -> bool { + false + } +} +#[stable(feature = "unix_socket_redox", since = "1.29")] +impl fmt::Debug for SocketAddr { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "SocketAddr") + } +} + +/// A Unix stream socket. +/// +/// # Examples +/// +/// ```no_run +/// use std::os::unix::net::UnixStream; +/// use std::io::prelude::*; +/// +/// let mut stream = UnixStream::connect("/path/to/my/socket").unwrap(); +/// stream.write_all(b"hello world").unwrap(); +/// let mut response = String::new(); +/// stream.read_to_string(&mut response).unwrap(); +/// println!("{}", response); +/// ``` +#[stable(feature = "unix_socket_redox", since = "1.29")] +pub struct UnixStream(FileDesc); + +#[stable(feature = "unix_socket_redox", since = "1.29")] +impl fmt::Debug for UnixStream { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let mut builder = fmt.debug_struct("UnixStream"); + builder.field("fd", &self.0.raw()); + if let Ok(addr) = self.local_addr() { + builder.field("local", &addr); + } + if let Ok(addr) = self.peer_addr() { + builder.field("peer", &addr); + } + builder.finish() + } +} + +impl UnixStream { + /// Connects to the socket named by `path`. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = match UnixStream::connect("/tmp/sock") { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't connect: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn connect>(path: P) -> io::Result { + if let Some(s) = path.as_ref().to_str() { + cvt(syscall::open(format!("chan:{}", s), syscall::O_CLOEXEC)) + .map(FileDesc::new) + .map(UnixStream) + } else { + Err(Error::new( + ErrorKind::Other, + "UnixStream::connect: non-utf8 paths not supported on redox" + )) + } + } + + /// Creates an unnamed pair of connected sockets. + /// + /// Returns two `UnixStream`s which are connected to each other. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let (sock1, sock2) = match UnixStream::pair() { + /// Ok((sock1, sock2)) => (sock1, sock2), + /// Err(e) => { + /// println!("Couldn't create a pair of sockets: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn pair() -> io::Result<(UnixStream, UnixStream)> { + let server = cvt(syscall::open("chan:", syscall::O_CREAT | syscall::O_CLOEXEC)) + .map(FileDesc::new)?; + let client = server.duplicate_path(b"connect")?; + let stream = server.duplicate_path(b"listen")?; + Ok((UnixStream(client), UnixStream(stream))) + } + + /// Creates a new independently owned handle to the underlying socket. + /// + /// The returned `UnixStream` is a reference to the same stream that this + /// object references. Both handles will read and write the same stream of + /// data, and options set on one stream will be propagated to the other + /// stream. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// let sock_copy = socket.try_clone().expect("Couldn't clone socket"); + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn try_clone(&self) -> io::Result { + self.0.duplicate().map(UnixStream) + } + + /// Returns the socket address of the local half of this connection. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn local_addr(&self) -> io::Result { + Err(Error::new(ErrorKind::Other, "UnixStream::local_addr unimplemented on redox")) + } + + /// Returns the socket address of the remote half of this connection. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// let addr = socket.peer_addr().expect("Couldn't get peer address"); + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn peer_addr(&self) -> io::Result { + Err(Error::new(ErrorKind::Other, "UnixStream::peer_addr unimplemented on redox")) + } + + /// Sets the read timeout for the socket. + /// + /// If the provided value is [`None`], then [`read`] calls will block + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method. + /// + /// [`None`]: ../../../../std/option/enum.Option.html#variant.None + /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err + /// [`read`]: ../../../../std/io/trait.Read.html#tymethod.read + /// [`Duration`]: ../../../../std/time/struct.Duration.html + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); + /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn set_read_timeout(&self, _timeout: Option) -> io::Result<()> { + Err(Error::new(ErrorKind::Other, "UnixStream::set_read_timeout unimplemented on redox")) + } + + /// Sets the write timeout for the socket. + /// + /// If the provided value is [`None`], then [`write`] calls will block + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is + /// passed to this method. + /// + /// [`None`]: ../../../../std/option/enum.Option.html#variant.None + /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err + /// [`write`]: ../../../../std/io/trait.Write.html#tymethod.write + /// [`Duration`]: ../../../../std/time/struct.Duration.html + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); + /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::net::UdpSocket; + /// use std::time::Duration; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").unwrap(); + /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn set_write_timeout(&self, _timeout: Option) -> io::Result<()> { + Err(Error::new(ErrorKind::Other, "UnixStream::set_write_timeout unimplemented on redox")) + } + + /// Returns the read timeout of this socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); + /// assert_eq!(socket.read_timeout().unwrap(), Some(Duration::new(1, 0))); + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn read_timeout(&self) -> io::Result> { + Err(Error::new(ErrorKind::Other, "UnixStream::read_timeout unimplemented on redox")) + } + + /// Returns the write timeout of this socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); + /// assert_eq!(socket.write_timeout().unwrap(), Some(Duration::new(1, 0))); + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn write_timeout(&self) -> io::Result> { + Err(Error::new(ErrorKind::Other, "UnixStream::write_timeout unimplemented on redox")) + } + + /// Moves the socket into or out of nonblocking mode. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.set_nonblocking(true).expect("Couldn't set nonblocking"); + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } + + /// Returns the value of the `SO_ERROR` option. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// if let Ok(Some(err)) = socket.take_error() { + /// println!("Got error: {:?}", err); + /// } + /// ``` + /// + /// # Platform specific + /// On Redox this always returns None. + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn take_error(&self) -> io::Result> { + Ok(None) + } + + /// Shuts down the read, write, or both halves of this connection. + /// + /// This function will cause all pending and future I/O calls on the + /// specified portions to immediately return with an appropriate value + /// (see the documentation of [`Shutdown`]). + /// + /// [`Shutdown`]: ../../../../std/net/enum.Shutdown.html + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::net::Shutdown; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.shutdown(Shutdown::Both).expect("shutdown function failed"); + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn shutdown(&self, _how: Shutdown) -> io::Result<()> { + Err(Error::new(ErrorKind::Other, "UnixStream::shutdown unimplemented on redox")) + } +} + +#[stable(feature = "unix_socket_redox", since = "1.29")] +impl io::Read for UnixStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + io::Read::read(&mut &*self, buf) + } + + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() + } +} + +#[stable(feature = "unix_socket_redox", since = "1.29")] +impl<'a> io::Read for &'a UnixStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } + + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() + } +} + +#[stable(feature = "unix_socket_redox", since = "1.29")] +impl io::Write for UnixStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + io::Write::write(&mut &*self, buf) + } + + fn flush(&mut self) -> io::Result<()> { + io::Write::flush(&mut &*self) + } +} + +#[stable(feature = "unix_socket_redox", since = "1.29")] +impl<'a> io::Write for &'a UnixStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +#[stable(feature = "unix_socket_redox", since = "1.29")] +impl AsRawFd for UnixStream { + fn as_raw_fd(&self) -> RawFd { + self.0.raw() + } +} + +#[stable(feature = "unix_socket_redox", since = "1.29")] +impl FromRawFd for UnixStream { + unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { + UnixStream(FileDesc::new(fd)) + } +} + +#[stable(feature = "unix_socket_redox", since = "1.29")] +impl IntoRawFd for UnixStream { + fn into_raw_fd(self) -> RawFd { + self.0.into_raw() + } +} + +/// A structure representing a Unix domain socket server. +/// +/// # Examples +/// +/// ```no_run +/// use std::thread; +/// use std::os::unix::net::{UnixStream, UnixListener}; +/// +/// fn handle_client(stream: UnixStream) { +/// // ... +/// } +/// +/// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); +/// +/// // accept connections and process them, spawning a new thread for each one +/// for stream in listener.incoming() { +/// match stream { +/// Ok(stream) => { +/// /* connection succeeded */ +/// thread::spawn(|| handle_client(stream)); +/// } +/// Err(err) => { +/// /* connection failed */ +/// break; +/// } +/// } +/// } +/// ``` +#[stable(feature = "unix_socket_redox", since = "1.29")] +pub struct UnixListener(FileDesc); + +#[stable(feature = "unix_socket_redox", since = "1.29")] +impl fmt::Debug for UnixListener { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let mut builder = fmt.debug_struct("UnixListener"); + builder.field("fd", &self.0.raw()); + if let Ok(addr) = self.local_addr() { + builder.field("local", &addr); + } + builder.finish() + } +} + +impl UnixListener { + /// Creates a new `UnixListener` bound to the specified socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = match UnixListener::bind("/path/to/the/socket") { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't connect: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn bind>(path: P) -> io::Result { + if let Some(s) = path.as_ref().to_str() { + cvt(syscall::open(format!("chan:{}", s), syscall::O_CREAT | syscall::O_CLOEXEC)) + .map(FileDesc::new) + .map(UnixListener) + } else { + Err(Error::new( + ErrorKind::Other, + "UnixListener::bind: non-utf8 paths not supported on redox" + )) + } + } + + /// Accepts a new incoming connection to this listener. + /// + /// This function will block the calling thread until a new Unix connection + /// is established. When established, the corresponding [`UnixStream`] and + /// the remote peer's address will be returned. + /// + /// [`UnixStream`]: ../../../../std/os/unix/net/struct.UnixStream.html + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); + /// + /// match listener.accept() { + /// Ok((socket, addr)) => println!("Got a client: {:?}", addr), + /// Err(e) => println!("accept function failed: {:?}", e), + /// } + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { + self.0.duplicate_path(b"listen").map(|fd| (UnixStream(fd), SocketAddr(()))) + } + + /// Creates a new independently owned handle to the underlying socket. + /// + /// The returned `UnixListener` is a reference to the same socket that this + /// object references. Both handles can be used to accept incoming + /// connections and options set on one listener will affect the other. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); + /// + /// let listener_copy = listener.try_clone().expect("try_clone failed"); + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn try_clone(&self) -> io::Result { + self.0.duplicate().map(UnixListener) + } + + /// Returns the local socket address of this listener. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); + /// + /// let addr = listener.local_addr().expect("Couldn't get local address"); + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn local_addr(&self) -> io::Result { + Err(Error::new(ErrorKind::Other, "UnixListener::local_addr unimplemented on redox")) + } + + /// Moves the socket into or out of nonblocking mode. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); + /// + /// listener.set_nonblocking(true).expect("Couldn't set non blocking"); + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } + + /// Returns the value of the `SO_ERROR` option. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = UnixListener::bind("/tmp/sock").unwrap(); + /// + /// if let Ok(Some(err)) = listener.take_error() { + /// println!("Got error: {:?}", err); + /// } + /// ``` + /// + /// # Platform specific + /// On Redox this always returns None. + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn take_error(&self) -> io::Result> { + Ok(None) + } + + /// Returns an iterator over incoming connections. + /// + /// The iterator will never return [`None`] and will also not yield the + /// peer's [`SocketAddr`] structure. + /// + /// [`None`]: ../../../../std/option/enum.Option.html#variant.None + /// [`SocketAddr`]: struct.SocketAddr.html + /// + /// # Examples + /// + /// ```no_run + /// use std::thread; + /// use std::os::unix::net::{UnixStream, UnixListener}; + /// + /// fn handle_client(stream: UnixStream) { + /// // ... + /// } + /// + /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); + /// + /// for stream in listener.incoming() { + /// match stream { + /// Ok(stream) => { + /// thread::spawn(|| handle_client(stream)); + /// } + /// Err(err) => { + /// break; + /// } + /// } + /// } + /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] + pub fn incoming<'a>(&'a self) -> Incoming<'a> { + Incoming { listener: self } + } +} + +#[stable(feature = "unix_socket_redox", since = "1.29")] +impl AsRawFd for UnixListener { + fn as_raw_fd(&self) -> RawFd { + self.0.raw() + } +} + +#[stable(feature = "unix_socket_redox", since = "1.29")] +impl FromRawFd for UnixListener { + unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { + UnixListener(FileDesc::new(fd)) + } +} + +#[stable(feature = "unix_socket_redox", since = "1.29")] +impl IntoRawFd for UnixListener { + fn into_raw_fd(self) -> RawFd { + self.0.into_raw() + } +} + +#[stable(feature = "unix_socket_redox", since = "1.29")] +impl<'a> IntoIterator for &'a UnixListener { + type Item = io::Result; + type IntoIter = Incoming<'a>; + + fn into_iter(self) -> Incoming<'a> { + self.incoming() + } +} + +/// An iterator over incoming connections to a [`UnixListener`]. +/// +/// It will never return [`None`]. +/// +/// [`None`]: ../../../../std/option/enum.Option.html#variant.None +/// [`UnixListener`]: struct.UnixListener.html +/// +/// # Examples +/// +/// ```no_run +/// use std::thread; +/// use std::os::unix::net::{UnixStream, UnixListener}; +/// +/// fn handle_client(stream: UnixStream) { +/// // ... +/// } +/// +/// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); +/// +/// for stream in listener.incoming() { +/// match stream { +/// Ok(stream) => { +/// thread::spawn(|| handle_client(stream)); +/// } +/// Err(err) => { +/// break; +/// } +/// } +/// } +/// ``` +#[derive(Debug)] +#[stable(feature = "unix_socket_redox", since = "1.29")] +pub struct Incoming<'a> { + listener: &'a UnixListener, +} + +#[stable(feature = "unix_socket_redox", since = "1.29")] +impl<'a> Iterator for Incoming<'a> { + type Item = io::Result; + + fn next(&mut self) -> Option> { + Some(self.listener.accept().map(|s| s.0)) + } + + fn size_hint(&self) -> (usize, Option) { + (usize::max_value(), None) + } +} diff --git a/ctr-std/src/sys/redox/fd.rs b/ctr-std/src/sys/redox/fd.rs index ba7bbdc..e04e279 100644 --- a/ctr-std/src/sys/redox/fd.rs +++ b/ctr-std/src/sys/redox/fd.rs @@ -47,7 +47,10 @@ impl FileDesc { } pub fn duplicate(&self) -> io::Result { - let new_fd = cvt(syscall::dup(self.fd, &[]))?; + self.duplicate_path(&[]) + } + pub fn duplicate_path(&self, path: &[u8]) -> io::Result { + let new_fd = cvt(syscall::dup(self.fd, path))?; Ok(FileDesc::new(new_fd)) } diff --git a/ctr-std/src/sys/redox/net/mod.rs b/ctr-std/src/sys/redox/net/mod.rs index 0291d7f..67f2223 100644 --- a/ctr-std/src/sys/redox/net/mod.rs +++ b/ctr-std/src/sys/redox/net/mod.rs @@ -41,12 +41,12 @@ impl Iterator for LookupHost { pub fn lookup_host(host: &str) -> Result { let mut ip_string = String::new(); File::open("/etc/net/ip")?.read_to_string(&mut ip_string)?; - let ip: Vec = ip_string.trim().split(".").map(|part| part.parse::() + let ip: Vec = ip_string.trim().split('.').map(|part| part.parse::() .unwrap_or(0)).collect(); let mut dns_string = String::new(); File::open("/etc/net/dns")?.read_to_string(&mut dns_string)?; - let dns: Vec = dns_string.trim().split(".").map(|part| part.parse::() + let dns: Vec = dns_string.trim().split('.').map(|part| part.parse::() .unwrap_or(0)).collect(); if ip.len() == 4 && dns.len() == 4 { diff --git a/ctr-std/src/sys/redox/net/netc.rs b/ctr-std/src/sys/redox/net/netc.rs index d443a4d..b6d9f45 100644 --- a/ctr-std/src/sys/redox/net/netc.rs +++ b/ctr-std/src/sys/redox/net/netc.rs @@ -24,10 +24,10 @@ pub struct in_addr { } #[derive(Copy, Clone)] +#[repr(align(4))] #[repr(C)] pub struct in6_addr { pub s6_addr: [u8; 16], - __align: [u32; 0], } #[derive(Copy, Clone)] diff --git a/ctr-std/src/sys/redox/net/udp.rs b/ctr-std/src/sys/redox/net/udp.rs index 2ed67bd..22af020 100644 --- a/ctr-std/src/sys/redox/net/udp.rs +++ b/ctr-std/src/sys/redox/net/udp.rs @@ -58,7 +58,7 @@ impl UdpSocket { pub fn recv(&self, buf: &mut [u8]) -> Result { if let Some(addr) = *self.get_conn() { - let from = self.0.dup(format!("{}", addr).as_bytes())?; + let from = self.0.dup(addr.to_string().as_bytes())?; from.read(buf) } else { Err(Error::new(ErrorKind::Other, "UdpSocket::recv not connected")) diff --git a/ctr-std/src/sys/redox/os.rs b/ctr-std/src/sys/redox/os.rs index 480765b..5822216 100644 --- a/ctr-std/src/sys/redox/os.rs +++ b/ctr-std/src/sys/redox/os.rs @@ -30,9 +30,6 @@ use sys_common::mutex::Mutex; use sys::{cvt, fd, syscall}; use vec; -const TMPBUF_SZ: usize = 128; -static ENV_LOCK: Mutex = Mutex::new(); - extern { #[link_name = "__errno_location"] fn errno_location() -> *mut i32; diff --git a/ctr-std/src/sys/redox/process.rs b/ctr-std/src/sys/redox/process.rs index d0b94e1..2037616 100644 --- a/ctr-std/src/sys/redox/process.rs +++ b/ctr-std/src/sys/redox/process.rs @@ -13,6 +13,7 @@ use ffi::OsStr; use os::unix::ffi::OsStrExt; use fmt; use io::{self, Error, ErrorKind}; +use iter; use libc::{EXIT_SUCCESS, EXIT_FAILURE}; use path::{Path, PathBuf}; use sys::fd::FileDesc; @@ -51,7 +52,7 @@ pub struct Command { uid: Option, gid: Option, saw_nul: bool, - closures: Vec io::Result<()> + Send + Sync>>, + closures: Vec io::Result<()> + Send + Sync>>, stdin: Option, stdout: Option, stderr: Option, @@ -122,7 +123,7 @@ impl Command { } pub fn before_exec(&mut self, - f: Box io::Result<()> + Send + Sync>) { + f: Box io::Result<()> + Send + Sync>) { self.closures.push(f); } @@ -296,11 +297,11 @@ impl Command { t!(callback()); } - let mut args: Vec<[usize; 2]> = Vec::new(); - args.push([self.program.as_ptr() as usize, self.program.len()]); - for arg in self.args.iter() { - args.push([arg.as_ptr() as usize, arg.len()]); - } + let args: Vec<[usize; 2]> = iter::once( + [self.program.as_ptr() as usize, self.program.len()] + ).chain( + self.args.iter().map(|arg| [arg.as_ptr() as usize, arg.len()]) + ).collect(); self.env.apply(); diff --git a/ctr-std/src/sys/redox/thread.rs b/ctr-std/src/sys/redox/thread.rs index 110d46c..f417708 100644 --- a/ctr-std/src/sys/redox/thread.rs +++ b/ctr-std/src/sys/redox/thread.rs @@ -28,7 +28,7 @@ unsafe impl Send for Thread {} unsafe impl Sync for Thread {} impl Thread { - pub unsafe fn new<'a>(_stack: usize, p: Box) -> io::Result { + pub unsafe fn new<'a>(_stack: usize, p: Box) -> io::Result { let p = box p; let id = cvt(syscall::clone(syscall::CLONE_VM | syscall::CLONE_FS | syscall::CLONE_FILES))?; diff --git a/ctr-std/src/sys/unix/args.rs b/ctr-std/src/sys/unix/args.rs index e1c7ffc..c3c033d 100644 --- a/ctr-std/src/sys/unix/args.rs +++ b/ctr-std/src/sys/unix/args.rs @@ -66,7 +66,8 @@ impl DoubleEndedIterator for Args { target_os = "emscripten", target_os = "haiku", target_os = "l4re", - target_os = "fuchsia"))] + target_os = "fuchsia", + target_os = "hermit"))] mod imp { use os::unix::prelude::*; use ptr; @@ -79,20 +80,20 @@ mod imp { static mut ARGC: isize = 0; static mut ARGV: *const *const u8 = ptr::null(); + // We never call `ENV_LOCK.init()`, so it is UB to attempt to + // acquire this mutex reentrantly! static LOCK: Mutex = Mutex::new(); pub unsafe fn init(argc: isize, argv: *const *const u8) { - LOCK.lock(); + let _guard = LOCK.lock(); ARGC = argc; ARGV = argv; - LOCK.unlock(); } pub unsafe fn cleanup() { - LOCK.lock(); + let _guard = LOCK.lock(); ARGC = 0; ARGV = ptr::null(); - LOCK.unlock(); } pub fn args() -> Args { @@ -104,13 +105,11 @@ mod imp { fn clone() -> Vec { unsafe { - LOCK.lock(); - let ret = (0..ARGC).map(|i| { + let _guard = LOCK.lock(); + (0..ARGC).map(|i| { let cstr = CStr::from_ptr(*ARGV.offset(i) as *const libc::c_char); OsStringExt::from_vec(cstr.to_bytes().to_vec()) - }).collect(); - LOCK.unlock(); - return ret + }).collect() } } } diff --git a/ctr-std/src/sys/unix/backtrace/tracing/gcc_s.rs b/ctr-std/src/sys/unix/backtrace/tracing/gcc_s.rs index 1b92fc0..6e84156 100644 --- a/ctr-std/src/sys/unix/backtrace/tracing/gcc_s.rs +++ b/ctr-std/src/sys/unix/backtrace/tracing/gcc_s.rs @@ -68,6 +68,10 @@ pub fn unwind_backtrace(frames: &mut [Frame]) extern fn trace_fn(ctx: *mut uw::_Unwind_Context, arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code { let cx = unsafe { &mut *(arg as *mut Context) }; + if cx.idx >= cx.frames.len() { + return uw::_URC_NORMAL_STOP; + } + let mut ip_before_insn = 0; let mut ip = unsafe { uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void @@ -94,14 +98,12 @@ extern fn trace_fn(ctx: *mut uw::_Unwind_Context, unsafe { uw::_Unwind_FindEnclosingFunction(ip) } }; - if cx.idx < cx.frames.len() { - cx.frames[cx.idx] = Frame { - symbol_addr: symaddr as *mut u8, - exact_position: ip as *mut u8, - inline_context: 0, - }; - cx.idx += 1; - } + cx.frames[cx.idx] = Frame { + symbol_addr: symaddr as *mut u8, + exact_position: ip as *mut u8, + inline_context: 0, + }; + cx.idx += 1; uw::_URC_NO_REASON } diff --git a/ctr-std/src/sys/unix/condvar.rs b/ctr-std/src/sys/unix/condvar.rs index 4f878d8..2007da7 100644 --- a/ctr-std/src/sys/unix/condvar.rs +++ b/ctr-std/src/sys/unix/condvar.rs @@ -41,13 +41,15 @@ impl Condvar { #[cfg(any(target_os = "macos", target_os = "ios", target_os = "l4re", - target_os = "android"))] + target_os = "android", + target_os = "hermit"))] pub unsafe fn init(&mut self) {} #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "l4re", - target_os = "android")))] + target_os = "android", + target_os = "hermit")))] pub unsafe fn init(&mut self) { use mem; let mut attr: libc::pthread_condattr_t = mem::uninitialized(); @@ -83,7 +85,10 @@ impl Condvar { // where we configure condition variable to use monotonic clock (instead of // default system clock). This approach avoids all problems that result // from changes made to the system time. - #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "android")))] + #[cfg(not(any(target_os = "macos", + target_os = "ios", + target_os = "android", + target_os = "hermit")))] pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { use mem; @@ -113,7 +118,7 @@ impl Condvar { // This implementation is modeled after libcxx's condition_variable // https://github.com/llvm-mirror/libcxx/blob/release_35/src/condition_variable.cpp#L46 // https://github.com/llvm-mirror/libcxx/blob/release_35/include/__mutex_base#L367 - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "android"))] + #[cfg(any(target_os = "macos", target_os = "ios", target_os = "android", target_os = "hermit"))] pub unsafe fn wait_timeout(&self, mutex: &Mutex, mut dur: Duration) -> bool { use ptr; use time::Instant; diff --git a/ctr-std/src/sys/unix/env.rs b/ctr-std/src/sys/unix/env.rs index 00cf7ec..ad116c5 100644 --- a/ctr-std/src/sys/unix/env.rs +++ b/ctr-std/src/sys/unix/env.rs @@ -172,3 +172,14 @@ pub mod os { pub const EXE_SUFFIX: &'static str = ""; pub const EXE_EXTENSION: &'static str = ""; } + +#[cfg(target_os = "hermit")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "hermit"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".so"; + pub const DLL_EXTENSION: &'static str = "so"; + pub const EXE_SUFFIX: &'static str = ""; + pub const EXE_EXTENSION: &'static str = ""; +} diff --git a/ctr-std/src/sys/unix/ext/fs.rs b/ctr-std/src/sys/unix/ext/fs.rs index 4e98101..507e9d8 100644 --- a/ctr-std/src/sys/unix/ext/fs.rs +++ b/ctr-std/src/sys/unix/ext/fs.rs @@ -59,6 +59,78 @@ pub trait FileExt { #[stable(feature = "file_offset", since = "1.15.0")] fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result; + /// Reads the exact number of byte required to fill `buf` from the given offset. + /// + /// The offset is relative to the start of the file and thus independent + /// from the current cursor. + /// + /// The current file cursor is not affected by this function. + /// + /// Similar to [`Read::read_exact`] but uses [`read_at`] instead of `read`. + /// + /// [`Read::read_exact`]: ../../../../std/io/trait.Read.html#method.read_exact + /// [`read_at`]: #tymethod.read_at + /// + /// # Errors + /// + /// If this function encounters an error of the kind + /// [`ErrorKind::Interrupted`] then the error is ignored and the operation + /// will continue. + /// + /// If this function encounters an "end of file" before completely filling + /// the buffer, it returns an error of the kind [`ErrorKind::UnexpectedEof`]. + /// The contents of `buf` are unspecified in this case. + /// + /// If any other read error is encountered then this function immediately + /// returns. The contents of `buf` are unspecified in this case. + /// + /// If this function returns an error, it is unspecified how many bytes it + /// has read, but it will never read more than would be necessary to + /// completely fill the buffer. + /// + /// [`ErrorKind::Interrupted`]: ../../../../std/io/enum.ErrorKind.html#variant.Interrupted + /// [`ErrorKind::UnexpectedEof`]: ../../../../std/io/enum.ErrorKind.html#variant.UnexpectedEof + /// + /// # Examples + /// + /// ```no_run + /// #![feature(rw_exact_all_at)] + /// use std::io; + /// use std::fs::File; + /// use std::os::unix::prelude::FileExt; + /// + /// fn main() -> io::Result<()> { + /// let mut buf = [0u8; 8]; + /// let file = File::open("foo.txt")?; + /// + /// // We now read exactly 8 bytes from the offset 10. + /// file.read_exact_at(&mut buf, 10)?; + /// println!("read {} bytes: {:?}", buf.len(), buf); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "rw_exact_all_at", issue = "51984")] + fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> { + while !buf.is_empty() { + match self.read_at(buf, offset) { + Ok(0) => break, + Ok(n) => { + let tmp = buf; + buf = &mut tmp[n..]; + offset += n as u64; + } + Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} + Err(e) => return Err(e), + } + } + if !buf.is_empty() { + Err(io::Error::new(io::ErrorKind::UnexpectedEof, + "failed to fill whole buffer")) + } else { + Ok(()) + } + } + /// Writes a number of bytes starting from a given offset. /// /// Returns the number of bytes written. @@ -93,6 +165,61 @@ pub trait FileExt { /// ``` #[stable(feature = "file_offset", since = "1.15.0")] fn write_at(&self, buf: &[u8], offset: u64) -> io::Result; + + /// Attempts to write an entire buffer starting from a given offset. + /// + /// The offset is relative to the start of the file and thus independent + /// from the current cursor. + /// + /// The current file cursor is not affected by this function. + /// + /// This method will continuously call [`write_at`] until there is no more data + /// to be written or an error of non-[`ErrorKind::Interrupted`] kind is + /// returned. This method will not return until the entire buffer has been + /// successfully written or such an error occurs. The first error that is + /// not of [`ErrorKind::Interrupted`] kind generated from this method will be + /// returned. + /// + /// # Errors + /// + /// This function will return the first error of + /// non-[`ErrorKind::Interrupted`] kind that [`write_at`] returns. + /// + /// [`ErrorKind::Interrupted`]: ../../../../std/io/enum.ErrorKind.html#variant.Interrupted + /// [`write_at`]: #tymethod.write_at + /// + /// # Examples + /// + /// ```no_run + /// #![feature(rw_exact_all_at)] + /// use std::fs::File; + /// use std::io; + /// use std::os::unix::prelude::FileExt; + /// + /// fn main() -> io::Result<()> { + /// let file = File::open("foo.txt")?; + /// + /// // We now write at the offset 10. + /// file.write_all_at(b"sushi", 10)?; + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "rw_exact_all_at", issue = "51984")] + fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> { + while !buf.is_empty() { + match self.write_at(buf, offset) { + Ok(0) => return Err(io::Error::new(io::ErrorKind::WriteZero, + "failed to write whole buffer")), + Ok(n) => { + buf = &buf[n..]; + offset += n as u64 + } + Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} + Err(e) => return Err(e), + } + } + Ok(()) + } } #[stable(feature = "file_offset", since = "1.15.0")] diff --git a/ctr-std/src/sys/unix/ext/mod.rs b/ctr-std/src/sys/unix/ext/mod.rs index c221f7c..88e4237 100644 --- a/ctr-std/src/sys/unix/ext/mod.rs +++ b/ctr-std/src/sys/unix/ext/mod.rs @@ -35,6 +35,7 @@ #![stable(feature = "rust1", since = "1.0.0")] #![doc(cfg(unix))] +#![allow(missing_docs)] pub mod io; pub mod ffi; diff --git a/ctr-std/src/sys/unix/ext/net.rs b/ctr-std/src/sys/unix/ext/net.rs index e277b1a..55f43cc 100644 --- a/ctr-std/src/sys/unix/ext/net.rs +++ b/ctr-std/src/sys/unix/ext/net.rs @@ -524,6 +524,9 @@ impl UnixStream { /// println!("Got error: {:?}", err); /// } /// ``` + /// + /// # Platform specific + /// On Redox this always returns None. #[stable(feature = "unix_socket", since = "1.10.0")] pub fn take_error(&self) -> io::Result> { self.0.take_error() @@ -846,6 +849,9 @@ impl UnixListener { /// println!("Got error: {:?}", err); /// } /// ``` + /// + /// # Platform specific + /// On Redox this always returns None. #[stable(feature = "unix_socket", since = "1.10.0")] pub fn take_error(&self) -> io::Result> { self.0.take_error() diff --git a/ctr-std/src/sys/unix/fast_thread_local.rs b/ctr-std/src/sys/unix/fast_thread_local.rs index 6cdbe5d..c13a0fe 100644 --- a/ctr-std/src/sys/unix/fast_thread_local.rs +++ b/ctr-std/src/sys/unix/fast_thread_local.rs @@ -20,7 +20,7 @@ // fallback implementation to use as well. // // Due to rust-lang/rust#18804, make sure this is not generic! -#[cfg(target_os = "linux")] +#[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "hermit"))] pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { use libc; use mem; @@ -55,11 +55,6 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { _tlv_atexit(dtor, t); } -// Just use the thread_local fallback implementation, at least until there's -// a more direct implementation. -#[cfg(target_os = "fuchsia")] -pub use sys_common::thread_local::register_dtor_fallback as register_dtor; - pub fn requires_move_before_drop() -> bool { // The macOS implementation of TLS apparently had an odd aspect to it // where the pointer we have may be overwritten while this destructor diff --git a/ctr-std/src/sys/unix/fs.rs b/ctr-std/src/sys/unix/fs.rs index 7743403..7a89d98 100644 --- a/ctr-std/src/sys/unix/fs.rs +++ b/ctr-std/src/sys/unix/fs.rs @@ -25,10 +25,12 @@ use sys_common::{AsInner, FromInner}; #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "l4re"))] use libc::{stat64, fstat64, lstat64, off64_t, ftruncate64, lseek64, dirent64, readdir64_r, open64}; +#[cfg(any(target_os = "linux", target_os = "emscripten"))] +use libc::fstatat64; #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))] -use libc::{fstatat, dirfd}; +use libc::dirfd; #[cfg(target_os = "android")] -use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, lseek64, +use libc::{stat as stat64, fstat as fstat64, fstatat as fstatat64, lstat as lstat64, lseek64, dirent as dirent64, open as open64}; #[cfg(not(any(target_os = "linux", target_os = "emscripten", @@ -57,7 +59,10 @@ struct InnerReadDir { } #[derive(Clone)] -pub struct ReadDir(Arc); +pub struct ReadDir { + inner: Arc, + end_of_stream: bool, +} struct Dir(*mut libc::DIR); @@ -213,7 +218,7 @@ impl fmt::Debug for ReadDir { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame. // Thus the result will be e g 'ReadDir("/home")' - fmt::Debug::fmt(&*self.0.root, f) + fmt::Debug::fmt(&*self.inner.root, f) } } @@ -229,7 +234,7 @@ impl Iterator for ReadDir { // is safe to use in threaded applications and it is generally preferred // over the readdir_r(3C) function. super::os::set_errno(0); - let entry_ptr = libc::readdir(self.0.dirp.0); + let entry_ptr = libc::readdir(self.inner.dirp.0); if entry_ptr.is_null() { // NULL can mean either the end is reached or an error occurred. // So we had to clear errno beforehand to check for an error now. @@ -257,6 +262,10 @@ impl Iterator for ReadDir { #[cfg(not(any(target_os = "solaris", target_os = "fuchsia")))] fn next(&mut self) -> Option> { + if self.end_of_stream { + return None; + } + unsafe { let mut ret = DirEntry { entry: mem::zeroed(), @@ -264,7 +273,14 @@ impl Iterator for ReadDir { }; let mut entry_ptr = ptr::null_mut(); loop { - if readdir64_r(self.0.dirp.0, &mut ret.entry, &mut entry_ptr) != 0 { + if readdir64_r(self.inner.dirp.0, &mut ret.entry, &mut entry_ptr) != 0 { + if entry_ptr.is_null() { + // We encountered an error (which will be returned in this iteration), but + // we also reached the end of the directory stream. The `end_of_stream` + // flag is enabled to make sure that we return `None` in the next iteration + // (instead of looping forever) + self.end_of_stream = true; + } return Some(Err(Error::last_os_error())) } if entry_ptr.is_null() { @@ -287,7 +303,7 @@ impl Drop for Dir { impl DirEntry { pub fn path(&self) -> PathBuf { - self.dir.0.root.join(OsStr::from_bytes(self.name_bytes())) + self.dir.inner.root.join(OsStr::from_bytes(self.name_bytes())) } pub fn file_name(&self) -> OsString { @@ -296,13 +312,10 @@ impl DirEntry { #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))] pub fn metadata(&self) -> io::Result { - let fd = cvt(unsafe {dirfd(self.dir.0.dirp.0)})?; + let fd = cvt(unsafe {dirfd(self.dir.inner.dirp.0)})?; let mut stat: stat64 = unsafe { mem::zeroed() }; cvt(unsafe { - fstatat(fd, - self.entry.d_name.as_ptr(), - &mut stat as *mut _ as *mut _, - libc::AT_SYMLINK_NOFOLLOW) + fstatat64(fd, self.entry.d_name.as_ptr(), &mut stat, libc::AT_SYMLINK_NOFOLLOW) })?; Ok(FileAttr { stat: stat }) } @@ -312,12 +325,12 @@ impl DirEntry { lstat(&self.path()) } - #[cfg(any(target_os = "solaris", target_os = "haiku"))] + #[cfg(any(target_os = "solaris", target_os = "haiku", target_os = "hermit"))] pub fn file_type(&self) -> io::Result { lstat(&self.path()).map(|m| m.file_type()) } - #[cfg(not(any(target_os = "solaris", target_os = "haiku")))] + #[cfg(not(any(target_os = "solaris", target_os = "haiku", target_os = "hermit")))] pub fn file_type(&self) -> io::Result { match self.entry.d_type { libc::DT_CHR => Ok(FileType { mode: libc::S_IFCHR }), @@ -339,7 +352,8 @@ impl DirEntry { target_os = "solaris", target_os = "haiku", target_os = "l4re", - target_os = "fuchsia"))] + target_os = "fuchsia", + target_os = "hermit"))] pub fn ino(&self) -> u64 { self.entry.d_ino as u64 } @@ -370,7 +384,8 @@ impl DirEntry { target_os = "linux", target_os = "emscripten", target_os = "l4re", - target_os = "haiku"))] + target_os = "haiku", + target_os = "hermit"))] fn name_bytes(&self) -> &[u8] { unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes() @@ -692,7 +707,10 @@ pub fn readdir(p: &Path) -> io::Result { Err(Error::last_os_error()) } else { let inner = InnerReadDir { dirp: Dir(ptr), root }; - Ok(ReadDir(Arc::new(inner))) + Ok(ReadDir{ + inner: Arc::new(inner), + end_of_stream: false, + }) } } } @@ -787,7 +805,7 @@ pub fn stat(p: &Path) -> io::Result { let p = cstr(p)?; let mut stat: stat64 = unsafe { mem::zeroed() }; cvt(unsafe { - stat64(p.as_ptr(), &mut stat as *mut _ as *mut _) + stat64(p.as_ptr(), &mut stat) })?; Ok(FileAttr { stat: stat }) } @@ -796,7 +814,7 @@ pub fn lstat(p: &Path) -> io::Result { let p = cstr(p)?; let mut stat: stat64 = unsafe { mem::zeroed() }; cvt(unsafe { - lstat64(p.as_ptr(), &mut stat as *mut _ as *mut _) + lstat64(p.as_ptr(), &mut stat) })?; Ok(FileAttr { stat: stat }) } diff --git a/ctr-std/src/sys/unix/mod.rs b/ctr-std/src/sys/unix/mod.rs index c1298e5..c738003 100644 --- a/ctr-std/src/sys/unix/mod.rs +++ b/ctr-std/src/sys/unix/mod.rs @@ -28,6 +28,7 @@ use libc; #[cfg(all(not(dox), target_os = "emscripten"))] pub use os::emscripten as platform; #[cfg(all(not(dox), target_os = "fuchsia"))] pub use os::fuchsia as platform; #[cfg(all(not(dox), target_os = "l4re"))] pub use os::linux as platform; +#[cfg(all(not(dox), target_os = "hermit"))] pub use os::hermit as platform; pub use self::rand::hashmap_random_keys; pub use libc::strlen; diff --git a/ctr-std/src/sys/unix/mutex.rs b/ctr-std/src/sys/unix/mutex.rs index 52cf3f9..1d447de 100644 --- a/ctr-std/src/sys/unix/mutex.rs +++ b/ctr-std/src/sys/unix/mutex.rs @@ -25,8 +25,10 @@ unsafe impl Sync for Mutex {} #[allow(dead_code)] // sys isn't exported yet impl Mutex { pub const fn new() -> Mutex { - // Might be moved and address is changing it is better to avoid - // initialization of potentially opaque OS data before it landed + // Might be moved to a different address, so it is better to avoid + // initialization of potentially opaque OS data before it landed. + // Be very careful using this newly constructed `Mutex`, reentrant + // locking is undefined behavior until `init` is called! Mutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) } } #[inline] @@ -49,9 +51,6 @@ impl Mutex { // references, we instead create the mutex with type // PTHREAD_MUTEX_NORMAL which is guaranteed to deadlock if we try to // re-lock it from the same thread, thus avoiding undefined behavior. - // - // We can't do anything for StaticMutex, but that type is deprecated - // anyways. let mut attr: libc::pthread_mutexattr_t = mem::uninitialized(); let r = libc::pthread_mutexattr_init(&mut attr); debug_assert_eq!(r, 0); diff --git a/ctr-std/src/sys/unix/os.rs b/ctr-std/src/sys/unix/os.rs index 4c86fdd..f8f0bbd 100644 --- a/ctr-std/src/sys/unix/os.rs +++ b/ctr-std/src/sys/unix/os.rs @@ -33,6 +33,8 @@ use sys::fd; use vec; const TMPBUF_SZ: usize = 128; +// We never call `ENV_LOCK.init()`, so it is UB to attempt to +// acquire this mutex reentrantly! static ENV_LOCK: Mutex = Mutex::new(); @@ -47,6 +49,7 @@ extern { target_os = "netbsd", target_os = "openbsd", target_os = "android", + target_os = "hermit", target_env = "newlib"), link_name = "__errno")] #[cfg_attr(target_os = "solaris", link_name = "___errno")] @@ -376,7 +379,7 @@ pub fn current_exe() -> io::Result { } } -#[cfg(any(target_os = "fuchsia", target_os = "l4re"))] +#[cfg(any(target_os = "fuchsia", target_os = "l4re", target_os = "hermit"))] pub fn current_exe() -> io::Result { use io::ErrorKind; Err(io::Error::new(ErrorKind::Other, "Not yet implemented!")) @@ -409,26 +412,19 @@ pub unsafe fn environ() -> *mut *const *const c_char { /// environment variables of the current process. pub fn env() -> Env { unsafe { - ENV_LOCK.lock(); + let _guard = ENV_LOCK.lock(); let mut environ = *environ(); - if environ == ptr::null() { - ENV_LOCK.unlock(); - panic!("os::env() failure getting env string from OS: {}", - io::Error::last_os_error()); - } let mut result = Vec::new(); - while *environ != ptr::null() { + while environ != ptr::null() && *environ != ptr::null() { if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) { result.push(key_value); } environ = environ.offset(1); } - let ret = Env { + return Env { iter: result.into_iter(), _dont_send_or_sync_me: PhantomData, - }; - ENV_LOCK.unlock(); - return ret + } } fn parse(input: &[u8]) -> Option<(OsString, OsString)> { @@ -452,15 +448,14 @@ pub fn getenv(k: &OsStr) -> io::Result> { // always None as well let k = CString::new(k.as_bytes())?; unsafe { - ENV_LOCK.lock(); + let _guard = ENV_LOCK.lock(); let s = libc::getenv(k.as_ptr()) as *const libc::c_char; let ret = if s.is_null() { None } else { Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec())) }; - ENV_LOCK.unlock(); - return Ok(ret) + Ok(ret) } } @@ -469,10 +464,8 @@ pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { let v = CString::new(v.as_bytes())?; unsafe { - ENV_LOCK.lock(); - let ret = cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(|_| ()); - ENV_LOCK.unlock(); - return ret + let _guard = ENV_LOCK.lock(); + cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(|_| ()) } } @@ -480,10 +473,8 @@ pub fn unsetenv(n: &OsStr) -> io::Result<()> { let nbuf = CString::new(n.as_bytes())?; unsafe { - ENV_LOCK.lock(); - let ret = cvt(libc::unsetenv(nbuf.as_ptr())).map(|_| ()); - ENV_LOCK.unlock(); - return ret + let _guard = ENV_LOCK.lock(); + cvt(libc::unsetenv(nbuf.as_ptr())).map(|_| ()) } } @@ -572,7 +563,7 @@ fn glibc_version_cstr() -> Option<&'static CStr> { // ignoring any extra dot-separated parts. Otherwise return None. #[cfg(target_env = "gnu")] fn parse_glibc_version(version: &str) -> Option<(usize, usize)> { - let mut parsed_ints = version.split(".").map(str::parse::).fuse(); + let mut parsed_ints = version.split('.').map(str::parse::).fuse(); match (parsed_ints.next(), parsed_ints.next()) { (Some(Ok(major)), Some(Ok(minor))) => Some((major, minor)), _ => None diff --git a/ctr-std/src/sys/unix/process/process_common.rs b/ctr-std/src/sys/unix/process/process_common.rs index 6396bb3..77f125f 100644 --- a/ctr-std/src/sys/unix/process/process_common.rs +++ b/ctr-std/src/sys/unix/process/process_common.rs @@ -52,7 +52,7 @@ pub struct Command { uid: Option, gid: Option, saw_nul: bool, - closures: Vec io::Result<()> + Send + Sync>>, + closures: Vec io::Result<()> + Send + Sync>>, stdin: Option, stdout: Option, stderr: Option, @@ -155,12 +155,12 @@ impl Command { self.gid } - pub fn get_closures(&mut self) -> &mut Vec io::Result<()> + Send + Sync>> { + pub fn get_closures(&mut self) -> &mut Vec io::Result<()> + Send + Sync>> { &mut self.closures } pub fn before_exec(&mut self, - f: Box io::Result<()> + Send + Sync>) { + f: Box io::Result<()> + Send + Sync>) { self.closures.push(f); } diff --git a/ctr-std/src/sys/unix/rand.rs b/ctr-std/src/sys/unix/rand.rs index caa1894..01c0ada 100644 --- a/ctr-std/src/sys/unix/rand.rs +++ b/ctr-std/src/sys/unix/rand.rs @@ -183,35 +183,10 @@ mod imp { mod imp { #[link(name = "zircon")] extern { - fn zx_cprng_draw(buffer: *mut u8, len: usize, actual: *mut usize) -> i32; - } - - fn getrandom(buf: &mut [u8]) -> Result { - unsafe { - let mut actual = 0; - let status = zx_cprng_draw(buf.as_mut_ptr(), buf.len(), &mut actual); - if status == 0 { - Ok(actual) - } else { - Err(status) - } - } + fn zx_cprng_draw(buffer: *mut u8, len: usize); } pub fn fill_bytes(v: &mut [u8]) { - let mut buf = v; - while !buf.is_empty() { - let ret = getrandom(buf); - match ret { - Err(err) => { - panic!("kernel zx_cprng_draw call failed! (returned {}, buf.len() {})", - err, buf.len()) - } - Ok(actual) => { - let move_buf = buf; - buf = &mut move_buf[(actual as usize)..]; - } - } - } + unsafe { zx_cprng_draw(v.as_mut_ptr(), v.len()) } } } diff --git a/ctr-std/src/sys/unix/thread.rs b/ctr-std/src/sys/unix/thread.rs index 7fdecc9..f3a45d2 100644 --- a/ctr-std/src/sys/unix/thread.rs +++ b/ctr-std/src/sys/unix/thread.rs @@ -49,7 +49,7 @@ unsafe fn pthread_attr_setstacksize(_attr: *mut libc::pthread_attr_t, } impl Thread { - pub unsafe fn new<'a>(stack: usize, p: Box) + pub unsafe fn new<'a>(stack: usize, p: Box) -> io::Result { let p = box p; let mut native: libc::pthread_t = mem::zeroed(); @@ -138,7 +138,8 @@ impl Thread { target_os = "solaris", target_os = "haiku", target_os = "l4re", - target_os = "emscripten"))] + target_os = "emscripten", + target_os = "hermit"))] pub fn set_name(_name: &CStr) { // Newlib, Illumos, Haiku, and Emscripten have no way to set a thread name. } diff --git a/ctr-std/src/sys/unix/time.rs b/ctr-std/src/sys/unix/time.rs index 89786eb..0b1fb72 100644 --- a/ctr-std/src/sys/unix/time.rs +++ b/ctr-std/src/sys/unix/time.rs @@ -345,9 +345,9 @@ mod inner { } } - #[cfg(not(target_os = "dragonfly"))] + #[cfg(not(any(target_os = "dragonfly", target_os = "hermit")))] pub type clock_t = libc::c_int; - #[cfg(target_os = "dragonfly")] + #[cfg(any(target_os = "dragonfly", target_os = "hermit"))] pub type clock_t = libc::c_ulong; fn now(clock: clock_t) -> Timespec { diff --git a/ctr-std/src/sys/wasm/os.rs b/ctr-std/src/sys/wasm/os.rs index 23ca175..0cb991e 100644 --- a/ctr-std/src/sys/wasm/os.rs +++ b/ctr-std/src/sys/wasm/os.rs @@ -21,7 +21,7 @@ pub fn errno() -> i32 { } pub fn error_string(_errno: i32) -> String { - format!("operation successful") + "operation successful".to_string() } pub fn getcwd() -> io::Result { diff --git a/ctr-std/src/sys/wasm/thread.rs b/ctr-std/src/sys/wasm/thread.rs index 728e678..8173a62 100644 --- a/ctr-std/src/sys/wasm/thread.rs +++ b/ctr-std/src/sys/wasm/thread.rs @@ -19,7 +19,7 @@ pub struct Thread(Void); pub const DEFAULT_MIN_STACK_SIZE: usize = 4096; impl Thread { - pub unsafe fn new<'a>(_stack: usize, _p: Box) + pub unsafe fn new<'a>(_stack: usize, _p: Box) -> io::Result { unsupported() diff --git a/ctr-std/src/sys/windows/backtrace/mod.rs b/ctr-std/src/sys/windows/backtrace/mod.rs index 82498ad..f64cae8 100644 --- a/ctr-std/src/sys/windows/backtrace/mod.rs +++ b/ctr-std/src/sys/windows/backtrace/mod.rs @@ -46,110 +46,281 @@ mod printing; #[path = "backtrace_gnu.rs"] pub mod gnu; -pub use self::printing::{resolve_symname, foreach_symbol_fileline}; +pub use self::printing::{foreach_symbol_fileline, resolve_symname}; +use self::printing::{load_printing_fns_64, load_printing_fns_ex}; -pub fn unwind_backtrace(frames: &mut [Frame]) - -> io::Result<(usize, BacktraceContext)> -{ +pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> { let dbghelp = DynamicLibrary::open("dbghelp.dll")?; // Fetch the symbols necessary from dbghelp.dll let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn)?; let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn)?; - let StackWalkEx = sym!(dbghelp, "StackWalkEx", StackWalkExFn)?; + + // StackWalkEx might not be present and we'll fall back to StackWalk64 + let sw_var = match sym!(dbghelp, "StackWalkEx", StackWalkExFn) { + Ok(StackWalkEx) => { + StackWalkVariant::StackWalkEx(StackWalkEx, load_printing_fns_ex(&dbghelp)?) + } + Err(e) => match sym!(dbghelp, "StackWalk64", StackWalk64Fn) { + Ok(StackWalk64) => { + StackWalkVariant::StackWalk64(StackWalk64, load_printing_fns_64(&dbghelp)?) + } + Err(..) => return Err(e), + }, + }; // Allocate necessary structures for doing the stack walk let process = unsafe { c::GetCurrentProcess() }; - let thread = unsafe { c::GetCurrentThread() }; - let mut context: c::CONTEXT = unsafe { mem::zeroed() }; - unsafe { c::RtlCaptureContext(&mut context) }; - let mut frame: c::STACKFRAME_EX = unsafe { mem::zeroed() }; - frame.StackFrameSize = mem::size_of_val(&frame) as c::DWORD; - let image = init_frame(&mut frame, &context); let backtrace_context = BacktraceContext { handle: process, SymCleanup, + StackWalkVariant: sw_var, dbghelp, }; // Initialize this process's symbols let ret = unsafe { SymInitialize(process, ptr::null_mut(), c::TRUE) }; if ret != c::TRUE { - return Ok((0, backtrace_context)) + return Ok((0, backtrace_context)); } // And now that we're done with all the setup, do the stack walking! + match backtrace_context.StackWalkVariant { + StackWalkVariant::StackWalkEx(StackWalkEx, _) => { + set_frames(StackWalkEx, frames).map(|i| (i, backtrace_context)) + } + + StackWalkVariant::StackWalk64(StackWalk64, _) => { + set_frames(StackWalk64, frames).map(|i| (i, backtrace_context)) + } + } +} + +fn set_frames(StackWalk: W, frames: &mut [Frame]) -> io::Result { + let process = unsafe { c::GetCurrentProcess() }; + let thread = unsafe { c::GetCurrentProcess() }; + let mut context: c::CONTEXT = unsafe { mem::zeroed() }; + unsafe { c::RtlCaptureContext(&mut context) }; + let mut frame = W::Item::new(); + let image = frame.init(&context); + let mut i = 0; - unsafe { - while i < frames.len() && - StackWalkEx(image, process, thread, &mut frame, &mut context, - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - 0) == c::TRUE - { - let addr = (frame.AddrPC.Offset - 1) as *const u8; - - frames[i] = Frame { - symbol_addr: addr, - exact_position: addr, - inline_context: frame.InlineFrameContext, - }; - i += 1; + while i < frames.len() + && StackWalk.walk(image, process, thread, &mut frame, &mut context) == c::TRUE + { + let addr = frame.get_addr(); + frames[i] = Frame { + symbol_addr: addr, + exact_position: addr, + inline_context: 0, + }; + + i += 1 + } + Ok(i) +} + +type SymInitializeFn = unsafe extern "system" fn(c::HANDLE, *mut c_void, c::BOOL) -> c::BOOL; +type SymCleanupFn = unsafe extern "system" fn(c::HANDLE) -> c::BOOL; + +type StackWalkExFn = unsafe extern "system" fn( + c::DWORD, + c::HANDLE, + c::HANDLE, + *mut c::STACKFRAME_EX, + *mut c::CONTEXT, + *mut c_void, + *mut c_void, + *mut c_void, + *mut c_void, + c::DWORD, +) -> c::BOOL; + +type StackWalk64Fn = unsafe extern "system" fn( + c::DWORD, + c::HANDLE, + c::HANDLE, + *mut c::STACKFRAME64, + *mut c::CONTEXT, + *mut c_void, + *mut c_void, + *mut c_void, + *mut c_void, +) -> c::BOOL; + +trait StackWalker { + type Item: StackFrame; + + fn walk(&self, c::DWORD, c::HANDLE, c::HANDLE, &mut Self::Item, &mut c::CONTEXT) -> c::BOOL; +} + +impl StackWalker for StackWalkExFn { + type Item = c::STACKFRAME_EX; + fn walk( + &self, + image: c::DWORD, + process: c::HANDLE, + thread: c::HANDLE, + frame: &mut Self::Item, + context: &mut c::CONTEXT, + ) -> c::BOOL { + unsafe { + self( + image, + process, + thread, + frame, + context, + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + 0, + ) + } + } +} + +impl StackWalker for StackWalk64Fn { + type Item = c::STACKFRAME64; + fn walk( + &self, + image: c::DWORD, + process: c::HANDLE, + thread: c::HANDLE, + frame: &mut Self::Item, + context: &mut c::CONTEXT, + ) -> c::BOOL { + unsafe { + self( + image, + process, + thread, + frame, + context, + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ) } } +} + +trait StackFrame { + fn new() -> Self; + fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD; + fn get_addr(&self) -> *const u8; +} + +impl StackFrame for c::STACKFRAME_EX { + fn new() -> c::STACKFRAME_EX { + unsafe { mem::zeroed() } + } + + #[cfg(target_arch = "x86")] + fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { + self.AddrPC.Offset = ctx.Eip as u64; + self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrStack.Offset = ctx.Esp as u64; + self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrFrame.Offset = ctx.Ebp as u64; + self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; + c::IMAGE_FILE_MACHINE_I386 + } + + #[cfg(target_arch = "x86_64")] + fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { + self.AddrPC.Offset = ctx.Rip as u64; + self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrStack.Offset = ctx.Rsp as u64; + self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrFrame.Offset = ctx.Rbp as u64; + self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; + c::IMAGE_FILE_MACHINE_AMD64 + } + + #[cfg(target_arch = "aarch64")] + fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { + self.AddrPC.Offset = ctx.Pc as u64; + self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrStack.Offset = ctx.Sp as u64; + self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrFrame.Offset = ctx.Fp as u64; + self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; + c::IMAGE_FILE_MACHINE_ARM64 + } - Ok((i, backtrace_context)) + fn get_addr(&self) -> *const u8 { + (self.AddrPC.Offset - 1) as *const u8 + } } -type SymInitializeFn = - unsafe extern "system" fn(c::HANDLE, *mut c_void, - c::BOOL) -> c::BOOL; -type SymCleanupFn = - unsafe extern "system" fn(c::HANDLE) -> c::BOOL; - -type StackWalkExFn = - unsafe extern "system" fn(c::DWORD, c::HANDLE, c::HANDLE, - *mut c::STACKFRAME_EX, *mut c::CONTEXT, - *mut c_void, *mut c_void, - *mut c_void, *mut c_void, c::DWORD) -> c::BOOL; - -#[cfg(target_arch = "x86")] -fn init_frame(frame: &mut c::STACKFRAME_EX, - ctx: &c::CONTEXT) -> c::DWORD { - frame.AddrPC.Offset = ctx.Eip as u64; - frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; - frame.AddrStack.Offset = ctx.Esp as u64; - frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; - frame.AddrFrame.Offset = ctx.Ebp as u64; - frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; - c::IMAGE_FILE_MACHINE_I386 +impl StackFrame for c::STACKFRAME64 { + fn new() -> c::STACKFRAME64 { + unsafe { mem::zeroed() } + } + + #[cfg(target_arch = "x86")] + fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { + self.AddrPC.Offset = ctx.Eip as u64; + self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrStack.Offset = ctx.Esp as u64; + self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrFrame.Offset = ctx.Ebp as u64; + self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; + c::IMAGE_FILE_MACHINE_I386 + } + + #[cfg(target_arch = "x86_64")] + fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { + self.AddrPC.Offset = ctx.Rip as u64; + self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrStack.Offset = ctx.Rsp as u64; + self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrFrame.Offset = ctx.Rbp as u64; + self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; + c::IMAGE_FILE_MACHINE_AMD64 + } + + #[cfg(target_arch = "aarch64")] + fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { + self.AddrPC.Offset = ctx.Pc as u64; + self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrStack.Offset = ctx.Sp as u64; + self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrFrame.Offset = ctx.Fp as u64; + self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; + c::IMAGE_FILE_MACHINE_ARM64 + } + + fn get_addr(&self) -> *const u8 { + (self.AddrPC.Offset - 1) as *const u8 + } } -#[cfg(target_arch = "x86_64")] -fn init_frame(frame: &mut c::STACKFRAME_EX, - ctx: &c::CONTEXT) -> c::DWORD { - frame.AddrPC.Offset = ctx.Rip as u64; - frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; - frame.AddrStack.Offset = ctx.Rsp as u64; - frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; - frame.AddrFrame.Offset = ctx.Rbp as u64; - frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; - c::IMAGE_FILE_MACHINE_AMD64 +enum StackWalkVariant { + StackWalkEx(StackWalkExFn, printing::PrintingFnsEx), + StackWalk64(StackWalk64Fn, printing::PrintingFns64), } pub struct BacktraceContext { handle: c::HANDLE, SymCleanup: SymCleanupFn, // Only used in printing for msvc and not gnu + // The gnu version is effectively a ZST dummy. + #[allow(dead_code)] + StackWalkVariant: StackWalkVariant, + // keeping DynamycLibrary loaded until its functions no longer needed #[allow(dead_code)] dbghelp: DynamicLibrary, } impl Drop for BacktraceContext { fn drop(&mut self) { - unsafe { (self.SymCleanup)(self.handle); } + unsafe { + (self.SymCleanup)(self.handle); + } } } diff --git a/ctr-std/src/sys/windows/backtrace/printing/mod.rs b/ctr-std/src/sys/windows/backtrace/printing/mod.rs index 3e566f6..251d502 100644 --- a/ctr-std/src/sys/windows/backtrace/printing/mod.rs +++ b/ctr-std/src/sys/windows/backtrace/printing/mod.rs @@ -15,6 +15,20 @@ mod printing; #[cfg(target_env = "gnu")] mod printing { pub use sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname}; + + // dummy functions to mirror those present in msvc version. + use sys::dynamic_lib::DynamicLibrary; + use io; + pub struct PrintingFnsEx {} + pub struct PrintingFns64 {} + pub fn load_printing_fns_ex(_: &DynamicLibrary) -> io::Result { + Ok(PrintingFnsEx{}) + } + pub fn load_printing_fns_64(_: &DynamicLibrary) -> io::Result { + Ok(PrintingFns64{}) + } } pub use self::printing::{foreach_symbol_fileline, resolve_symname}; +pub use self::printing::{load_printing_fns_ex, load_printing_fns_64, + PrintingFnsEx, PrintingFns64}; diff --git a/ctr-std/src/sys/windows/backtrace/printing/msvc.rs b/ctr-std/src/sys/windows/backtrace/printing/msvc.rs index 967df1c..c8b946b 100644 --- a/ctr-std/src/sys/windows/backtrace/printing/msvc.rs +++ b/ctr-std/src/sys/windows/backtrace/printing/msvc.rs @@ -10,29 +10,108 @@ use ffi::CStr; use io; -use libc::{c_ulong, c_char}; +use libc::{c_char, c_ulong}; use mem; -use sys::c; use sys::backtrace::BacktraceContext; +use sys::backtrace::StackWalkVariant; +use sys::c; +use sys::dynamic_lib::DynamicLibrary; use sys_common::backtrace::Frame; +// Structs holding printing functions and loaders for them +// Two versions depending on whether dbghelp.dll has StackWalkEx or not +// (the former being in newer Windows versions, the older being in Win7 and before) +pub struct PrintingFnsEx { + resolve_symname: SymFromInlineContextFn, + sym_get_line: SymGetLineFromInlineContextFn, +} +pub struct PrintingFns64 { + resolve_symname: SymFromAddrFn, + sym_get_line: SymGetLineFromAddr64Fn, +} + +pub fn load_printing_fns_ex(dbghelp: &DynamicLibrary) -> io::Result { + Ok(PrintingFnsEx { + resolve_symname: sym!(dbghelp, "SymFromInlineContext", SymFromInlineContextFn)?, + sym_get_line: sym!( + dbghelp, + "SymGetLineFromInlineContext", + SymGetLineFromInlineContextFn + )?, + }) +} +pub fn load_printing_fns_64(dbghelp: &DynamicLibrary) -> io::Result { + Ok(PrintingFns64 { + resolve_symname: sym!(dbghelp, "SymFromAddr", SymFromAddrFn)?, + sym_get_line: sym!(dbghelp, "SymGetLineFromAddr64", SymGetLineFromAddr64Fn)?, + }) +} + +type SymFromAddrFn = + unsafe extern "system" fn(c::HANDLE, u64, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL; type SymFromInlineContextFn = - unsafe extern "system" fn(c::HANDLE, u64, c::ULONG, - *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL; -type SymGetLineFromInlineContextFn = - unsafe extern "system" fn(c::HANDLE, u64, c::ULONG, - u64, *mut c::DWORD, *mut c::IMAGEHLP_LINE64) -> c::BOOL; + unsafe extern "system" fn(c::HANDLE, u64, c::ULONG, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL; + +type SymGetLineFromAddr64Fn = + unsafe extern "system" fn(c::HANDLE, u64, *mut u32, *mut c::IMAGEHLP_LINE64) -> c::BOOL; +type SymGetLineFromInlineContextFn = unsafe extern "system" fn( + c::HANDLE, + u64, + c::ULONG, + u64, + *mut c::DWORD, + *mut c::IMAGEHLP_LINE64, +) -> c::BOOL; /// Converts a pointer to symbol to its string value. -pub fn resolve_symname(frame: Frame, - callback: F, - context: &BacktraceContext) -> io::Result<()> - where F: FnOnce(Option<&str>) -> io::Result<()> +pub fn resolve_symname(frame: Frame, callback: F, context: &BacktraceContext) -> io::Result<()> +where + F: FnOnce(Option<&str>) -> io::Result<()>, { - let SymFromInlineContext = sym!(&context.dbghelp, - "SymFromInlineContext", - SymFromInlineContextFn)?; + match context.StackWalkVariant { + StackWalkVariant::StackWalkEx(_, ref fns) => resolve_symname_internal( + |process: c::HANDLE, + symbol_address: u64, + inline_context: c::ULONG, + info: *mut c::SYMBOL_INFO| unsafe { + let mut displacement = 0u64; + (fns.resolve_symname)( + process, + symbol_address, + inline_context, + &mut displacement, + info, + ) + }, + frame, + callback, + context, + ), + StackWalkVariant::StackWalk64(_, ref fns) => resolve_symname_internal( + |process: c::HANDLE, + symbol_address: u64, + _inline_context: c::ULONG, + info: *mut c::SYMBOL_INFO| unsafe { + let mut displacement = 0u64; + (fns.resolve_symname)(process, symbol_address, &mut displacement, info) + }, + frame, + callback, + context, + ), + } +} +fn resolve_symname_internal( + mut symbol_resolver: R, + frame: Frame, + callback: F, + context: &BacktraceContext, +) -> io::Result<()> +where + F: FnOnce(Option<&str>) -> io::Result<()>, + R: FnMut(c::HANDLE, u64, c::ULONG, *mut c::SYMBOL_INFO) -> c::BOOL, +{ unsafe { let mut info: c::SYMBOL_INFO = mem::zeroed(); info.MaxNameLen = c::MAX_SYM_NAME as c_ulong; @@ -41,14 +120,13 @@ pub fn resolve_symname(frame: Frame, // due to struct alignment. info.SizeOfStruct = 88; - let mut displacement = 0u64; - let ret = SymFromInlineContext(context.handle, - frame.symbol_addr as u64, - frame.inline_context, - &mut displacement, - &mut info); - let valid_range = if ret == c::TRUE && - frame.symbol_addr as usize >= info.Address as usize { + let ret = symbol_resolver( + context.handle, + frame.symbol_addr as u64, + frame.inline_context, + &mut info, + ); + let valid_range = if ret == c::TRUE && frame.symbol_addr as usize >= info.Address as usize { if info.Size != 0 { (frame.symbol_addr as usize) < info.Address as usize + info.Size as usize } else { @@ -67,30 +145,72 @@ pub fn resolve_symname(frame: Frame, } } -pub fn foreach_symbol_fileline(frame: Frame, - mut f: F, - context: &BacktraceContext) - -> io::Result - where F: FnMut(&[u8], u32) -> io::Result<()> +pub fn foreach_symbol_fileline( + frame: Frame, + callback: F, + context: &BacktraceContext, +) -> io::Result +where + F: FnMut(&[u8], u32) -> io::Result<()>, { - let SymGetLineFromInlineContext = sym!(&context.dbghelp, - "SymGetLineFromInlineContext", - SymGetLineFromInlineContextFn)?; + match context.StackWalkVariant { + StackWalkVariant::StackWalkEx(_, ref fns) => foreach_symbol_fileline_iternal( + |process: c::HANDLE, + frame_address: u64, + inline_context: c::ULONG, + line: *mut c::IMAGEHLP_LINE64| unsafe { + let mut displacement = 0u32; + (fns.sym_get_line)( + process, + frame_address, + inline_context, + 0, + &mut displacement, + line, + ) + }, + frame, + callback, + context, + ), + StackWalkVariant::StackWalk64(_, ref fns) => foreach_symbol_fileline_iternal( + |process: c::HANDLE, + frame_address: u64, + _inline_context: c::ULONG, + line: *mut c::IMAGEHLP_LINE64| unsafe { + let mut displacement = 0u32; + (fns.sym_get_line)(process, frame_address, &mut displacement, line) + }, + frame, + callback, + context, + ), + } +} +fn foreach_symbol_fileline_iternal( + mut line_getter: G, + frame: Frame, + mut callback: F, + context: &BacktraceContext, +) -> io::Result +where + F: FnMut(&[u8], u32) -> io::Result<()>, + G: FnMut(c::HANDLE, u64, c::ULONG, *mut c::IMAGEHLP_LINE64) -> c::BOOL, +{ unsafe { let mut line: c::IMAGEHLP_LINE64 = mem::zeroed(); line.SizeOfStruct = ::mem::size_of::() as u32; - let mut displacement = 0u32; - let ret = SymGetLineFromInlineContext(context.handle, - frame.exact_position as u64, - frame.inline_context, - 0, - &mut displacement, - &mut line); + let ret = line_getter( + context.handle, + frame.exact_position as u64, + frame.inline_context, + &mut line, + ); if ret == c::TRUE { let name = CStr::from_ptr(line.Filename).to_bytes(); - f(name, line.LineNumber as u32)?; + callback(name, line.LineNumber as u32)?; } Ok(false) } diff --git a/ctr-std/src/sys/windows/c.rs b/ctr-std/src/sys/windows/c.rs index 6d929f2..e514a56 100644 --- a/ctr-std/src/sys/windows/c.rs +++ b/ctr-std/src/sys/windows/c.rs @@ -280,6 +280,9 @@ pub const IMAGE_FILE_MACHINE_I386: DWORD = 0x014c; #[cfg(target_arch = "x86_64")] #[cfg(feature = "backtrace")] pub const IMAGE_FILE_MACHINE_AMD64: DWORD = 0x8664; +#[cfg(target_arch = "aarch64")] +#[cfg(feature = "backtrace")] +pub const IMAGE_FILE_MACHINE_ARM64: DWORD = 0xAA64; pub const EXCEPTION_CONTINUE_SEARCH: LONG = 0; pub const EXCEPTION_STACK_OVERFLOW: DWORD = 0xc00000fd; @@ -296,6 +299,8 @@ pub const PIPE_READMODE_BYTE: DWORD = 0x00000000; pub const FD_SETSIZE: usize = 64; +pub const STACK_SIZE_PARAM_IS_A_RESERVATION: DWORD = 0x00010000; + #[repr(C)] #[cfg(not(target_pointer_width = "64"))] pub struct WSADATA { @@ -635,6 +640,22 @@ pub struct STACKFRAME_EX { pub InlineFrameContext: DWORD, } +#[repr(C)] +#[cfg(feature = "backtrace")] +pub struct STACKFRAME64 { + pub AddrPC: ADDRESS64, + pub AddrReturn: ADDRESS64, + pub AddrFrame: ADDRESS64, + pub AddrStack: ADDRESS64, + pub AddrBStore: ADDRESS64, + pub FuncTableEntry: *mut c_void, + pub Params: [u64; 4], + pub Far: BOOL, + pub Virtual: BOOL, + pub Reserved: [u64; 3], + pub KdHelp: KDHELP64, +} + #[repr(C)] #[cfg(feature = "backtrace")] pub struct KDHELP64 { @@ -773,9 +794,68 @@ pub struct FLOATING_SAVE_AREA { // will not appear in the final documentation. This should be also defined for // other architectures supported by Windows such as ARM, and for historical // interest, maybe MIPS and PowerPC as well. -#[cfg(all(dox, not(any(target_arch = "x86_64", target_arch = "x86"))))] +#[cfg(all(dox, not(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64"))))] pub enum CONTEXT {} +#[cfg(target_arch = "aarch64")] +pub const ARM64_MAX_BREAKPOINTS: usize = 8; + +#[cfg(target_arch = "aarch64")] +pub const ARM64_MAX_WATCHPOINTS: usize = 2; + +#[cfg(target_arch = "aarch64")] +#[repr(C)] +pub struct ARM64_NT_NEON128 { + pub D: [f64; 2], +} + +#[cfg(target_arch = "aarch64")] +#[repr(C, align(16))] +pub struct CONTEXT { + pub ContextFlags: DWORD, + pub Cpsr: DWORD, + pub X0: u64, + pub X1: u64, + pub X2: u64, + pub X3: u64, + pub X4: u64, + pub X5: u64, + pub X6: u64, + pub X7: u64, + pub X8: u64, + pub X9: u64, + pub X10: u64, + pub X11: u64, + pub X12: u64, + pub X13: u64, + pub X14: u64, + pub X15: u64, + pub X16: u64, + pub X17: u64, + pub X18: u64, + pub X19: u64, + pub X20: u64, + pub X21: u64, + pub X22: u64, + pub X23: u64, + pub X24: u64, + pub X25: u64, + pub X26: u64, + pub X27: u64, + pub X28: u64, + pub Fp: u64, + pub Lr: u64, + pub Sp: u64, + pub Pc: u64, + pub V: [ARM64_NT_NEON128; 32], + pub Fpcr: DWORD, + pub Fpsr: DWORD, + pub Bcr: [DWORD; ARM64_MAX_BREAKPOINTS], + pub Bvr: [DWORD; ARM64_MAX_BREAKPOINTS], + pub Wcr: [DWORD; ARM64_MAX_WATCHPOINTS], + pub Wvr: [DWORD; ARM64_MAX_WATCHPOINTS], +} + #[repr(C)] pub struct SOCKADDR_STORAGE_LH { pub ss_family: ADDRESS_FAMILY, diff --git a/ctr-std/src/sys/windows/ext/ffi.rs b/ctr-std/src/sys/windows/ext/ffi.rs index 98d4355..bae0d02 100644 --- a/ctr-std/src/sys/windows/ext/ffi.rs +++ b/ctr-std/src/sys/windows/ext/ffi.rs @@ -31,7 +31,7 @@ //! //! If Rust code *does* need to look into those strings, it can //! convert them to valid UTF-8, possibly lossily, by substituting -//! invalid sequences with U+FFFD REPLACEMENT CHARACTER, as is +//! invalid sequences with [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD], as is //! conventionally done in other Rust APIs that deal with string //! encodings. //! @@ -65,6 +65,7 @@ //! [`from_wide`]: trait.OsStringExt.html#tymethod.from_wide //! [`encode_wide`]: trait.OsStrExt.html#tymethod.encode_wide //! [`collect`]: ../../../iter/trait.Iterator.html#method.collect +//! [U+FFFD]: ../../../char/constant.REPLACEMENT_CHARACTER.html #![stable(feature = "rust1", since = "1.0.0")] diff --git a/ctr-std/src/sys/windows/ext/mod.rs b/ctr-std/src/sys/windows/ext/mod.rs index 4b458d2..1f10609 100644 --- a/ctr-std/src/sys/windows/ext/mod.rs +++ b/ctr-std/src/sys/windows/ext/mod.rs @@ -18,6 +18,7 @@ #![stable(feature = "rust1", since = "1.0.0")] #![doc(cfg(windows))] +#![allow(missing_docs)] pub mod ffi; pub mod fs; diff --git a/ctr-std/src/sys/windows/mod.rs b/ctr-std/src/sys/windows/mod.rs index 0d12ecf..ccf79de 100644 --- a/ctr-std/src/sys/windows/mod.rs +++ b/ctr-std/src/sys/windows/mod.rs @@ -266,8 +266,12 @@ pub fn dur2timeout(dur: Duration) -> c::DWORD { // handlers. // // https://msdn.microsoft.com/en-us/library/dn774154.aspx -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +#[allow(unreachable_code)] pub unsafe fn abort_internal() -> ! { - asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT - ::intrinsics::unreachable(); + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + { + asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT + ::intrinsics::unreachable(); + } + ::intrinsics::abort(); } diff --git a/ctr-std/src/sys/windows/process.rs b/ctr-std/src/sys/windows/process.rs index be442f4..4974a8d 100644 --- a/ctr-std/src/sys/windows/process.rs +++ b/ctr-std/src/sys/windows/process.rs @@ -487,9 +487,7 @@ fn make_command_line(prog: &OsStr, args: &[OsString]) -> io::Result> { } else { if x == '"' as u16 { // Add n+1 backslashes to total 2n+1 before internal '"'. - for _ in 0..(backslashes+1) { - cmd.push('\\' as u16); - } + cmd.extend((0..(backslashes + 1)).map(|_| '\\' as u16)); } backslashes = 0; } @@ -498,9 +496,7 @@ fn make_command_line(prog: &OsStr, args: &[OsString]) -> io::Result> { if quote { // Add n backslashes to total 2n before ending '"'. - for _ in 0..backslashes { - cmd.push('\\' as u16); - } + cmd.extend((0..backslashes).map(|_| '\\' as u16)); cmd.push('"' as u16); } Ok(()) diff --git a/ctr-std/src/sys/windows/thread.rs b/ctr-std/src/sys/windows/thread.rs index b6f6330..85588cc 100644 --- a/ctr-std/src/sys/windows/thread.rs +++ b/ctr-std/src/sys/windows/thread.rs @@ -28,7 +28,7 @@ pub struct Thread { } impl Thread { - pub unsafe fn new<'a>(stack: usize, p: Box) + pub unsafe fn new<'a>(stack: usize, p: Box) -> io::Result { let p = box p; @@ -42,7 +42,8 @@ impl Thread { let stack_size = (stack + 0xfffe) & (!0xfffe); let ret = c::CreateThread(ptr::null_mut(), stack_size, thread_start, &*p as *const _ as *mut _, - 0, ptr::null_mut()); + c::STACK_SIZE_PARAM_IS_A_RESERVATION, + ptr::null_mut()); return if ret as usize == 0 { Err(io::Error::last_os_error()) diff --git a/ctr-std/src/sys_common/at_exit_imp.rs b/ctr-std/src/sys_common/at_exit_imp.rs index 26da51c..76e5df2 100644 --- a/ctr-std/src/sys_common/at_exit_imp.rs +++ b/ctr-std/src/sys_common/at_exit_imp.rs @@ -14,17 +14,22 @@ use boxed::FnBox; use ptr; +use mem; use sys_common::mutex::Mutex; -type Queue = Vec>; +type Queue = Vec>; // NB these are specifically not types from `std::sync` as they currently rely // on poisoning and this module needs to operate at a lower level than requiring // the thread infrastructure to be in place (useful on the borders of // initialization/destruction). +// We never call `LOCK.init()`, so it is UB to attempt to +// acquire this mutex reentrantly! static LOCK: Mutex = Mutex::new(); static mut QUEUE: *mut Queue = ptr::null_mut(); +const DONE: *mut Queue = 1_usize as *mut _; + // The maximum number of times the cleanup routines will be run. While running // the at_exit closures new ones may be registered, and this count is the number // of times the new closures will be allowed to register successfully. After @@ -35,7 +40,7 @@ unsafe fn init() -> bool { if QUEUE.is_null() { let state: Box = box Vec::new(); QUEUE = Box::into_raw(state); - } else if QUEUE as usize == 1 { + } else if QUEUE == DONE { // can't re-init after a cleanup return false } @@ -44,20 +49,21 @@ unsafe fn init() -> bool { } pub fn cleanup() { - for i in 0..ITERS { + for i in 1..=ITERS { unsafe { - LOCK.lock(); - let queue = QUEUE; - QUEUE = if i == ITERS - 1 {1} else {0} as *mut _; - LOCK.unlock(); + let queue = { + let _guard = LOCK.lock(); + mem::replace(&mut QUEUE, if i == ITERS { DONE } else { ptr::null_mut() }) + }; // make sure we're not recursively cleaning up - assert!(queue as usize != 1); + assert!(queue != DONE); // If we never called init, not need to cleanup! - if queue as usize != 0 { + if !queue.is_null() { let queue: Box = Box::from_raw(queue); for to_run in *queue { + // We are not holding any lock, so reentrancy is fine. to_run(); } } @@ -65,16 +71,16 @@ pub fn cleanup() { } } -pub fn push(f: Box) -> bool { - let mut ret = true; +pub fn push(f: Box) -> bool { unsafe { - LOCK.lock(); + let _guard = LOCK.lock(); if init() { + // We are just moving `f` around, not calling it. + // There is no possibility of reentrancy here. (*QUEUE).push(f); + true } else { - ret = false; + false } - LOCK.unlock(); } - ret } diff --git a/ctr-std/src/sys_common/backtrace.rs b/ctr-std/src/sys_common/backtrace.rs index 20109d2..7737178 100644 --- a/ctr-std/src/sys_common/backtrace.rs +++ b/ctr-std/src/sys_common/backtrace.rs @@ -49,7 +49,7 @@ pub struct Frame { const MAX_NB_FRAMES: usize = 100; /// Prints the current backtrace. -pub fn print(w: &mut Write, format: PrintFormat) -> io::Result<()> { +pub fn print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> { static LOCK: Mutex = Mutex::new(); // Use a lock to prevent mixed output in multithreading context. @@ -62,7 +62,7 @@ pub fn print(w: &mut Write, format: PrintFormat) -> io::Result<()> { } } -fn _print(w: &mut Write, format: PrintFormat) -> io::Result<()> { +fn _print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> { let mut frames = [Frame { exact_position: ptr::null(), symbol_addr: ptr::null(), @@ -156,16 +156,15 @@ pub fn log_enabled() -> Option { _ => return Some(PrintFormat::Full), } - let val = match env::var_os("RUST_BACKTRACE") { - Some(x) => if &x == "0" { + let val = env::var_os("RUST_BACKTRACE").and_then(|x| + if &x == "0" { None } else if &x == "full" { Some(PrintFormat::Full) } else { Some(PrintFormat::Short) - }, - None => None, - }; + } + ); ENABLED.store(match val { Some(v) => v as isize, None => 1, @@ -177,7 +176,7 @@ pub fn log_enabled() -> Option { /// /// These output functions should now be used everywhere to ensure consistency. /// You may want to also use `output_fileline`. -fn output(w: &mut Write, idx: usize, frame: Frame, +fn output(w: &mut dyn Write, idx: usize, frame: Frame, s: Option<&str>, format: PrintFormat) -> io::Result<()> { // Remove the `17: 0x0 - ` line. if format == PrintFormat::Short && frame.exact_position == ptr::null() { @@ -202,7 +201,7 @@ fn output(w: &mut Write, idx: usize, frame: Frame, /// /// See also `output`. #[allow(dead_code)] -fn output_fileline(w: &mut Write, +fn output_fileline(w: &mut dyn Write, file: &[u8], line: u32, format: PrintFormat) -> io::Result<()> { @@ -254,7 +253,7 @@ fn output_fileline(w: &mut Write, // Note that this demangler isn't quite as fancy as it could be. We have lots // of other information in our symbols like hashes, version, type information, // etc. Additionally, this doesn't handle glue symbols at all. -pub fn demangle(writer: &mut Write, mut s: &str, format: PrintFormat) -> io::Result<()> { +pub fn demangle(writer: &mut dyn Write, mut s: &str, format: PrintFormat) -> io::Result<()> { // During ThinLTO LLVM may import and rename internal symbols, so strip out // those endings first as they're one of the last manglings applied to // symbol names. @@ -263,7 +262,7 @@ pub fn demangle(writer: &mut Write, mut s: &str, format: PrintFormat) -> io::Res let candidate = &s[i + llvm.len()..]; let all_hex = candidate.chars().all(|c| { match c { - 'A' ... 'F' | '0' ... '9' => true, + 'A' ..= 'F' | '0' ..= '9' => true, _ => false, } }); diff --git a/ctr-std/src/sys_common/mutex.rs b/ctr-std/src/sys_common/mutex.rs index d1a7387..c6d531c 100644 --- a/ctr-std/src/sys_common/mutex.rs +++ b/ctr-std/src/sys_common/mutex.rs @@ -24,11 +24,17 @@ impl Mutex { /// /// Behavior is undefined if the mutex is moved after it is /// first used with any of the functions below. + /// Also, until `init` is called, behavior is undefined if this + /// mutex is ever used reentrantly, i.e., `raw_lock` or `try_lock` + /// are called by the thread currently holding the lock. pub const fn new() -> Mutex { Mutex(imp::Mutex::new()) } /// Prepare the mutex for use. /// /// This should be called once the mutex is at a stable memory address. + /// If called, this must be the very first thing that happens to the mutex. + /// Calling it in parallel with or after any operation (including another + /// `init()`) is undefined behavior. #[inline] pub unsafe fn init(&mut self) { self.0.init() } @@ -37,7 +43,15 @@ impl Mutex { /// Behavior is undefined if the mutex has been moved between this and any /// previous function call. #[inline] - pub unsafe fn lock(&self) { self.0.lock() } + pub unsafe fn raw_lock(&self) { self.0.lock() } + + /// Calls raw_lock() and then returns an RAII guard to guarantee the mutex + /// will be unlocked. + #[inline] + pub unsafe fn lock(&self) -> MutexGuard { + self.raw_lock(); + MutexGuard(&self.0) + } /// Attempts to lock the mutex without blocking, returning whether it was /// successfully acquired or not. @@ -51,8 +65,11 @@ impl Mutex { /// /// Behavior is undefined if the current thread does not actually hold the /// mutex. + /// + /// Consider switching from the pair of raw_lock() and raw_unlock() to + /// lock() whenever possible. #[inline] - pub unsafe fn unlock(&self) { self.0.unlock() } + pub unsafe fn raw_unlock(&self) { self.0.unlock() } /// Deallocates all resources associated with this mutex. /// @@ -64,3 +81,14 @@ impl Mutex { // not meant to be exported to the outside world, just the containing module pub fn raw(mutex: &Mutex) -> &imp::Mutex { &mutex.0 } + +#[must_use] +/// A simple RAII utility for the above Mutex without the poisoning semantics. +pub struct MutexGuard<'a>(&'a imp::Mutex); + +impl<'a> Drop for MutexGuard<'a> { + #[inline] + fn drop(&mut self) { + unsafe { self.0.unlock(); } + } +} diff --git a/ctr-std/src/sys_common/poison.rs b/ctr-std/src/sys_common/poison.rs index e74c40a..1625efe 100644 --- a/ctr-std/src/sys_common/poison.rs +++ b/ctr-std/src/sys_common/poison.rs @@ -251,7 +251,7 @@ impl Error for TryLockError { } } - fn cause(&self) -> Option<&Error> { + fn cause(&self) -> Option<&dyn Error> { match *self { TryLockError::Poisoned(ref p) => Some(p), _ => None diff --git a/ctr-std/src/sys_common/remutex.rs b/ctr-std/src/sys_common/remutex.rs index 022056f..071a3a2 100644 --- a/ctr-std/src/sys_common/remutex.rs +++ b/ctr-std/src/sys_common/remutex.rs @@ -13,6 +13,7 @@ use marker; use ops::Deref; use sys_common::poison::{self, TryLockError, TryLockResult, LockResult}; use sys::mutex as sys; +use panic::{UnwindSafe, RefUnwindSafe}; /// A re-entrant mutual exclusion /// @@ -28,6 +29,9 @@ pub struct ReentrantMutex { unsafe impl Send for ReentrantMutex {} unsafe impl Sync for ReentrantMutex {} +impl UnwindSafe for ReentrantMutex {} +impl RefUnwindSafe for ReentrantMutex {} + /// An RAII implementation of a "scoped lock" of a mutex. When this structure is /// dropped (falls out of scope), the lock will be unlocked. diff --git a/ctr-std/src/sys_common/thread.rs b/ctr-std/src/sys_common/thread.rs index da6f58e..86a5e2b 100644 --- a/ctr-std/src/sys_common/thread.rs +++ b/ctr-std/src/sys_common/thread.rs @@ -21,7 +21,7 @@ pub unsafe fn start_thread(main: *mut u8) { let _handler = stack_overflow::Handler::new(); // Finally, let's run some code. - Box::from_raw(main as *mut Box)() + Box::from_raw(main as *mut Box)() } pub fn min_stack() -> usize { diff --git a/ctr-std/src/sys_common/thread_local.rs b/ctr-std/src/sys_common/thread_local.rs index d0d6224..bb72cb0 100644 --- a/ctr-std/src/sys_common/thread_local.rs +++ b/ctr-std/src/sys_common/thread_local.rs @@ -161,14 +161,15 @@ impl StaticKey { // Additionally a 0-index of a tls key hasn't been seen on windows, so // we just simplify the whole branch. if imp::requires_synchronized_create() { + // We never call `INIT_LOCK.init()`, so it is UB to attempt to + // acquire this mutex reentrantly! static INIT_LOCK: Mutex = Mutex::new(); - INIT_LOCK.lock(); + let _guard = INIT_LOCK.lock(); let mut key = self.key.load(Ordering::SeqCst); if key == 0 { key = imp::create(self.dtor) as usize; self.key.store(key, Ordering::SeqCst); } - INIT_LOCK.unlock(); rtassert!(key != 0); return key } diff --git a/ctr-std/src/sys_common/wtf8.rs b/ctr-std/src/sys_common/wtf8.rs index 14a2555..45204b5 100644 --- a/ctr-std/src/sys_common/wtf8.rs +++ b/ctr-std/src/sys_common/wtf8.rs @@ -76,7 +76,7 @@ impl CodePoint { #[inline] pub fn from_u32(value: u32) -> Option { match value { - 0 ... 0x10FFFF => Some(CodePoint { value: value }), + 0 ..= 0x10FFFF => Some(CodePoint { value: value }), _ => None } } @@ -101,7 +101,7 @@ impl CodePoint { #[inline] pub fn to_char(&self) -> Option { match self.value { - 0xD800 ... 0xDFFF => None, + 0xD800 ..= 0xDFFF => None, _ => Some(unsafe { char::from_u32_unchecked(self.value) }) } } @@ -305,7 +305,7 @@ impl Wtf8Buf { /// like concatenating ill-formed UTF-16 strings effectively would. #[inline] pub fn push(&mut self, code_point: CodePoint) { - if let trail @ 0xDC00...0xDFFF = code_point.to_u32() { + if let trail @ 0xDC00..=0xDFFF = code_point.to_u32() { if let Some(lead) = (&*self).final_lead_surrogate() { let len_without_lead_surrogate = self.len() - 3; self.bytes.truncate(len_without_lead_surrogate); @@ -525,7 +525,7 @@ impl Wtf8 { #[inline] pub fn ascii_byte_at(&self, position: usize) -> u8 { match self.bytes[position] { - ascii_byte @ 0x00 ... 0x7F => ascii_byte, + ascii_byte @ 0x00 ..= 0x7F => ascii_byte, _ => 0xFF } } @@ -630,7 +630,7 @@ impl Wtf8 { return None } match &self.bytes[(len - 3)..] { - &[0xED, b2 @ 0xA0...0xAF, b3] => Some(decode_surrogate(b2, b3)), + &[0xED, b2 @ 0xA0..=0xAF, b3] => Some(decode_surrogate(b2, b3)), _ => None } } @@ -642,7 +642,7 @@ impl Wtf8 { return None } match &self.bytes[..3] { - &[0xED, b2 @ 0xB0...0xBF, b3] => Some(decode_surrogate(b2, b3)), + &[0xED, b2 @ 0xB0..=0xBF, b3] => Some(decode_surrogate(b2, b3)), _ => None } } @@ -1245,7 +1245,7 @@ mod tests { #[test] fn wtf8_display() { fn d(b: &[u8]) -> String { - format!("{}", &unsafe { Wtf8::from_bytes_unchecked(b) }) + (&unsafe { Wtf8::from_bytes_unchecked(b) }).to_string() } assert_eq!("", d("".as_bytes())); diff --git a/ctr-std/src/tests/env.rs b/ctr-std/src/tests/env.rs index d437652..8acb8a4 100644 --- a/ctr-std/src/tests/env.rs +++ b/ctr-std/src/tests/env.rs @@ -11,7 +11,6 @@ extern crate rand; use std::env::*; -use std::iter::repeat; use std::ffi::{OsString, OsStr}; use rand::Rng; @@ -72,7 +71,7 @@ fn test_var_big() { #[cfg_attr(target_os = "emscripten", ignore)] fn test_env_set_get_huge() { let n = make_rand_name(); - let s = repeat("x").take(10000).collect::(); + let s = "x".repeat(10000); set_var(&n, &s); eq(var_os(&n), Some(&s)); remove_var(&n); diff --git a/ctr-std/src/thread/local.rs b/ctr-std/src/thread/local.rs index 40d3280..a170abb 100644 --- a/ctr-std/src/thread/local.rs +++ b/ctr-std/src/thread/local.rs @@ -276,7 +276,7 @@ impl LocalKey { /// /// This will lazily initialize the value if this thread has not referenced /// this key yet. If the key has been destroyed (which may happen if this is called - /// in a destructor), this function will return a `ThreadLocalError`. + /// in a destructor), this function will return an [`AccessError`](struct.AccessError.html). /// /// # Panics /// diff --git a/ctr-std/src/thread/mod.rs b/ctr-std/src/thread/mod.rs index 1b976b7..61c6084 100644 --- a/ctr-std/src/thread/mod.rs +++ b/ctr-std/src/thread/mod.rs @@ -731,7 +731,8 @@ const NOTIFIED: usize = 2; /// specifying a maximum time to block the thread for. /// /// * The [`unpark`] method on a [`Thread`] atomically makes the token available -/// if it wasn't already. +/// if it wasn't already. Because the token is initially absent, [`unpark`] +/// followed by [`park`] will result in the second call returning immediately. /// /// In other words, each [`Thread`] acts a bit like a spinlock that can be /// locked and unlocked using `park` and `unpark`. @@ -766,6 +767,8 @@ const NOTIFIED: usize = 2; /// // Let some time pass for the thread to be spawned. /// thread::sleep(Duration::from_millis(10)); /// +/// // There is no race condition here, if `unpark` +/// // happens first, `park` will return immediately. /// println!("Unpark the thread"); /// parked_thread.thread().unpark(); /// @@ -796,7 +799,10 @@ pub fn park() { let mut m = thread.inner.lock.lock().unwrap(); match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) { Ok(_) => {} - Err(NOTIFIED) => return, // notified after we locked + Err(NOTIFIED) => { + thread.inner.state.store(EMPTY, SeqCst); + return; + } // should consume this notification, so prohibit spurious wakeups in next park. Err(_) => panic!("inconsistent park state"), } loop { @@ -882,7 +888,10 @@ pub fn park_timeout(dur: Duration) { let m = thread.inner.lock.lock().unwrap(); match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) { Ok(_) => {} - Err(NOTIFIED) => return, // notified after we locked + Err(NOTIFIED) => { + thread.inner.state.store(EMPTY, SeqCst); + return; + } // should consume this notification, so prohibit spurious wakeups in next park. Err(_) => panic!("inconsistent park_timeout state"), } @@ -931,24 +940,23 @@ pub struct ThreadId(u64); impl ThreadId { // Generate a new unique thread ID. fn new() -> ThreadId { + // We never call `GUARD.init()`, so it is UB to attempt to + // acquire this mutex reentrantly! static GUARD: mutex::Mutex = mutex::Mutex::new(); static mut COUNTER: u64 = 0; unsafe { - GUARD.lock(); + let _guard = GUARD.lock(); // If we somehow use up all our bits, panic so that we're not // covering up subtle bugs of IDs being reused. if COUNTER == ::u64::MAX { - GUARD.unlock(); panic!("failed to generate unique thread ID: bitspace exhausted"); } let id = COUNTER; COUNTER += 1; - GUARD.unlock(); - ThreadId(id) } } @@ -1172,7 +1180,7 @@ impl fmt::Debug for Thread { /// /// [`Result`]: ../../std/result/enum.Result.html #[stable(feature = "rust1", since = "1.0.0")] -pub type Result = ::result::Result>; +pub type Result = ::result::Result>; // This packet is used to communicate the return value between the child thread // and the parent thread. Memory is shared through the `Arc` within and there's @@ -1273,6 +1281,11 @@ impl JoinInner { #[stable(feature = "rust1", since = "1.0.0")] pub struct JoinHandle(JoinInner); +#[stable(feature = "joinhandle_impl_send_sync", since = "1.29.0")] +unsafe impl Send for JoinHandle {} +#[stable(feature = "joinhandle_impl_send_sync", since = "1.29.0")] +unsafe impl Sync for JoinHandle {} + impl JoinHandle { /// Extracts a handle to the underlying thread. /// @@ -1435,7 +1448,7 @@ mod tests { rx.recv().unwrap(); } - fn avoid_copying_the_body(spawnfn: F) where F: FnOnce(Box) { + fn avoid_copying_the_body(spawnfn: F) where F: FnOnce(Box) { let (tx, rx) = channel(); let x: Box<_> = box 1; @@ -1482,7 +1495,7 @@ mod tests { // (well, it would if the constant were 8000+ - I lowered it to be more // valgrind-friendly. try this at home, instead..!) const GENERATIONS: u32 = 16; - fn child_no(x: u32) -> Box { + fn child_no(x: u32) -> Box { return Box::new(move|| { if x < GENERATIONS { thread::spawn(move|| child_no(x+1)()); @@ -1528,10 +1541,10 @@ mod tests { #[test] fn test_try_panic_message_any() { match thread::spawn(move|| { - panic!(box 413u16 as Box); + panic!(box 413u16 as Box); }).join() { Err(e) => { - type T = Box; + type T = Box; assert!(e.is::()); let any = e.downcast::().unwrap(); assert!(any.is::()); diff --git a/ctru-rs/src/lib.rs b/ctru-rs/src/lib.rs index c3caf62..ea7b58e 100644 --- a/ctru-rs/src/lib.rs +++ b/ctru-rs/src/lib.rs @@ -2,7 +2,6 @@ #![crate_name = "ctru"] #![feature(fnbox)] -#![feature(thread_local_state)] #[macro_use] extern crate bitflags;