about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorMichał Krasnoborski <mkrdln@gmail.com>2017-02-03 17:48:07 +0100
committerMichał Krasnoborski <mkrdln@gmail.com>2017-02-03 17:48:07 +0100
commit0267529681e2fac6ef4560afe7d8d439d04e6303 (patch)
tree00bac1c7b714a59f1e4f230a64cb5427de2b62eb /src/libstd
parentecda7f314fa79bbfbf2125c99fd66288ca83c875 (diff)
parentaed6410a7b0f15dc68536e0735787436526ba395 (diff)
downloadrust-0267529681e2fac6ef4560afe7d8d439d04e6303.tar.gz
rust-0267529681e2fac6ef4560afe7d8d439d04e6303.zip
Merge remote-tracking branch 'upstream/master' into format-with-capacity
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/build.rs38
-rw-r--r--src/libstd/env.rs2
-rw-r--r--src/libstd/fs.rs3
-rw-r--r--src/libstd/net/addr.rs8
-rw-r--r--src/libstd/net/ip.rs8
-rw-r--r--src/libstd/sys/redox/ext/fs.rs10
-rw-r--r--src/libstd/sys/unix/backtrace/mod.rs11
-rw-r--r--src/libstd/sys/unix/pipe.rs39
-rw-r--r--src/libstd/sys/windows/backtrace.rs4
-rw-r--r--src/libstd/sys/windows/backtrace_gnu.rs62
-rw-r--r--src/libstd/sys/windows/c.rs40
-rw-r--r--src/libstd/sys/windows/ext/process.rs6
-rw-r--r--src/libstd/sys/windows/mod.rs47
-rw-r--r--src/libstd/sys_common/gnu/libbacktrace.rs17
-rw-r--r--src/libstd/thread/mod.rs4
-rw-r--r--src/libstd/time/duration.rs16
16 files changed, 241 insertions, 74 deletions
diff --git a/src/libstd/build.rs b/src/libstd/build.rs
index 5e1c3a28515..a0844821709 100644
--- a/src/libstd/build.rs
+++ b/src/libstd/build.rs
@@ -10,14 +10,15 @@
 
 #![deny(warnings)]
 
-extern crate gcc;
+#[macro_use]
 extern crate build_helper;
+extern crate gcc;
 
 use std::env;
-use std::path::PathBuf;
+use std::fs::{self, File};
+use std::path::{Path, PathBuf};
 use std::process::Command;
-
-use build_helper::run;
+use build_helper::{run, rerun_if_changed_anything_in_dir, up_to_date};
 
 fn main() {
     println!("cargo:rustc-cfg=cargobuild");
@@ -66,29 +67,25 @@ fn main() {
 }
 
 fn build_libbacktrace(host: &str, target: &str) {
-    let src_dir = env::current_dir().unwrap().join("../libbacktrace");
-    let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
+    let build_dir = env::var_os("RUSTBUILD_NATIVE_DIR").unwrap_or(env::var_os("OUT_DIR").unwrap());
+    let build_dir = PathBuf::from(build_dir).join("libbacktrace");
+    let _ = fs::create_dir_all(&build_dir);
 
     println!("cargo:rustc-link-lib=static=backtrace");
     println!("cargo:rustc-link-search=native={}/.libs", build_dir.display());
-
-    let mut stack = src_dir.read_dir().unwrap()
-                           .map(|e| e.unwrap())
-                           .collect::<Vec<_>>();
-    while let Some(entry) = stack.pop() {
-        let path = entry.path();
-        if entry.file_type().unwrap().is_dir() {
-            stack.extend(path.read_dir().unwrap().map(|e| e.unwrap()));
-        } else {
-            println!("cargo:rerun-if-changed={}", path.display());
-        }
+    let src_dir = env::current_dir().unwrap().join("../libbacktrace");
+    rerun_if_changed_anything_in_dir(&src_dir);
+    let timestamp = build_dir.join("rustbuild.timestamp");
+    if up_to_date(&Path::new("build.rs"), &timestamp) && up_to_date(&src_dir, &timestamp) {
+        return
     }
 
     let compiler = gcc::Config::new().get_compiler();
     // only msvc returns None for ar so unwrap is okay
     let ar = build_helper::cc2ar(compiler.path(), target).unwrap();
-    let cflags = compiler.args().iter().map(|s| s.to_str().unwrap())
-                         .collect::<Vec<_>>().join(" ");
+    let mut cflags = compiler.args().iter().map(|s| s.to_str().unwrap())
+                             .collect::<Vec<_>>().join(" ");
+    cflags.push_str(" -fvisibility=hidden");
     run(Command::new("sh")
                 .current_dir(&build_dir)
                 .arg(src_dir.join("configure").to_str().unwrap()
@@ -104,8 +101,11 @@ fn build_libbacktrace(host: &str, target: &str) {
                 .env("AR", &ar)
                 .env("RANLIB", format!("{} s", ar.display()))
                 .env("CFLAGS", cflags));
+
     run(Command::new(build_helper::make(host))
                 .current_dir(&build_dir)
                 .arg(format!("INCDIR={}", src_dir.display()))
                 .arg("-j").arg(env::var("NUM_JOBS").expect("NUM_JOBS was not set")));
+
+    t!(File::create(&timestamp));
 }
diff --git a/src/libstd/env.rs b/src/libstd/env.rs
index 80c64ae860f..c3a6b2433ed 100644
--- a/src/libstd/env.rs
+++ b/src/libstd/env.rs
@@ -222,7 +222,7 @@ fn _var_os(key: &OsStr) -> Option<OsString> {
 
 /// Possible errors from the [`env::var`] function.
 ///
-/// [env::var]: fn.var.html
+/// [`env::var`]: fn.var.html
 #[derive(Debug, PartialEq, Eq, Clone)]
 #[stable(feature = "env", since = "1.0.0")]
 pub enum VarError {
diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs
index f1dc36ae793..249627c430c 100644
--- a/src/libstd/fs.rs
+++ b/src/libstd/fs.rs
@@ -404,7 +404,6 @@ impl File {
     /// # Examples
     ///
     /// ```
-    /// #![feature(set_permissions_atomic)]
     /// # fn foo() -> std::io::Result<()> {
     /// use std::fs::File;
     ///
@@ -415,7 +414,7 @@ impl File {
     /// # Ok(())
     /// # }
     /// ```
-    #[unstable(feature = "set_permissions_atomic", issue="37916")]
+    #[stable(feature = "set_permissions_atomic", since = "1.16.0")]
     pub fn set_permissions(&self, perm: Permissions) -> io::Result<()> {
         self.inner.set_permissions(perm.0)
     }
diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs
index d186a53311d..751878c687c 100644
--- a/src/libstd/net/addr.rs
+++ b/src/libstd/net/addr.rs
@@ -148,8 +148,6 @@ impl SocketAddr {
     /// # Examples
     ///
     /// ```
-    /// #![feature(sockaddr_checker)]
-    ///
     /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
     ///
     /// fn main() {
@@ -158,7 +156,7 @@ impl SocketAddr {
     ///     assert_eq!(socket.is_ipv6(), false);
     /// }
     /// ```
-    #[unstable(feature = "sockaddr_checker", issue = "36949")]
+    #[stable(feature = "sockaddr_checker", since = "1.16.0")]
     pub fn is_ipv4(&self) -> bool {
         match *self {
             SocketAddr::V4(_) => true,
@@ -172,8 +170,6 @@ impl SocketAddr {
     /// # Examples
     ///
     /// ```
-    /// #![feature(sockaddr_checker)]
-    ///
     /// use std::net::{IpAddr, Ipv6Addr, SocketAddr};
     ///
     /// fn main() {
@@ -183,7 +179,7 @@ impl SocketAddr {
     ///     assert_eq!(socket.is_ipv6(), true);
     /// }
     /// ```
-    #[unstable(feature = "sockaddr_checker", issue = "36949")]
+    #[stable(feature = "sockaddr_checker", since = "1.16.0")]
     pub fn is_ipv6(&self) -> bool {
         match *self {
             SocketAddr::V4(_) => false,
diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs
index 05e3d38b17e..7803cf728f2 100644
--- a/src/libstd/net/ip.rs
+++ b/src/libstd/net/ip.rs
@@ -196,8 +196,6 @@ impl IpAddr {
     /// # Examples
     ///
     /// ```
-    /// #![feature(ipaddr_checker)]
-    ///
     /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
     ///
     /// fn main() {
@@ -206,7 +204,7 @@ impl IpAddr {
     ///                false);
     /// }
     /// ```
-    #[unstable(feature = "ipaddr_checker", issue = "36949")]
+    #[stable(feature = "ipaddr_checker", since = "1.16.0")]
     pub fn is_ipv4(&self) -> bool {
         match *self {
             IpAddr::V4(_) => true,
@@ -219,8 +217,6 @@ impl IpAddr {
     /// # Examples
     ///
     /// ```
-    /// #![feature(ipaddr_checker)]
-    ///
     /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
     ///
     /// fn main() {
@@ -229,7 +225,7 @@ impl IpAddr {
     ///                true);
     /// }
     /// ```
-    #[unstable(feature = "ipaddr_checker", issue = "36949")]
+    #[stable(feature = "ipaddr_checker", since = "1.16.0")]
     pub fn is_ipv6(&self) -> bool {
         match *self {
             IpAddr::V4(_) => false,
diff --git a/src/libstd/sys/redox/ext/fs.rs b/src/libstd/sys/redox/ext/fs.rs
index 7ad8d27b483..fc81cc737d9 100644
--- a/src/libstd/sys/redox/ext/fs.rs
+++ b/src/libstd/sys/redox/ext/fs.rs
@@ -161,6 +161,10 @@ impl OpenOptionsExt for OpenOptions {
 #[stable(feature = "metadata_ext", since = "1.1.0")]
 pub trait MetadataExt {
     #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn dev(&self) -> u64;
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn ino(&self) -> u64;
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
     fn mode(&self) -> u32;
     #[stable(feature = "metadata_ext", since = "1.1.0")]
     fn uid(&self) -> u32;
@@ -184,6 +188,12 @@ pub trait MetadataExt {
 
 #[stable(feature = "metadata_ext", since = "1.1.0")]
 impl MetadataExt for fs::Metadata {
+    fn dev(&self) -> u64 {
+        self.as_inner().as_inner().st_dev as u64
+    }
+    fn ino(&self) -> u64 {
+        self.as_inner().as_inner().st_ino as u64
+    }
     fn mode(&self) -> u32 {
         self.as_inner().as_inner().st_mode as u32
     }
diff --git a/src/libstd/sys/unix/backtrace/mod.rs b/src/libstd/sys/unix/backtrace/mod.rs
index d7c05e513f6..1eef89bf66f 100644
--- a/src/libstd/sys/unix/backtrace/mod.rs
+++ b/src/libstd/sys/unix/backtrace/mod.rs
@@ -89,3 +89,14 @@ pub use self::tracing::write;
 mod tracing;
 // symbol resolvers:
 mod printing;
+
+#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "emscripten")))]
+pub mod gnu {
+    use io;
+    use fs;
+    use libc::c_char;
+
+    pub fn get_executable_filename() -> io::Result<(Vec<c_char>, fs::File)> {
+        Err(io::Error::new(io::ErrorKind::Other, "Not implemented"))
+    }
+}
diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs
index a8ed415b7f4..51e00fc1ab9 100644
--- a/src/libstd/sys/unix/pipe.rs
+++ b/src/libstd/sys/unix/pipe.rs
@@ -13,7 +13,7 @@ use io;
 use libc::{self, c_int};
 use mem;
 use ptr;
-use sys::cvt_r;
+use sys::{cvt, cvt_r};
 use sys::fd::FileDesc;
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -29,34 +29,29 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
     // CLOEXEC flag is to use the `pipe2` syscall on Linux. This was added in
     // 2.6.27, however, and because we support 2.6.18 we must detect this
     // support dynamically.
-    if cfg!(target_os = "linux") {
+    if cfg!(any(target_os = "dragonfly",
+                target_os = "freebsd",
+                target_os = "linux",
+                target_os = "netbsd",
+                target_os = "openbsd"))
+    {
         weak! { fn pipe2(*mut c_int, c_int) -> c_int }
         if let Some(pipe) = pipe2.get() {
-            match cvt_r(|| unsafe { pipe(fds.as_mut_ptr(), libc::O_CLOEXEC) }) {
-                Ok(_) => {
-                    return Ok((AnonPipe(FileDesc::new(fds[0])),
-                               AnonPipe(FileDesc::new(fds[1]))))
-                }
-                Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {}
-                Err(e) => return Err(e),
-            }
+            cvt(unsafe { pipe(fds.as_mut_ptr(), libc::O_CLOEXEC) })?;
+            return Ok((AnonPipe(FileDesc::new(fds[0])),
+                       AnonPipe(FileDesc::new(fds[1]))));
         }
     }
-    if unsafe { libc::pipe(fds.as_mut_ptr()) == 0 } {
-        let fd0 = FileDesc::new(fds[0]);
-        let fd1 = FileDesc::new(fds[1]);
-        Ok((AnonPipe::from_fd(fd0)?, AnonPipe::from_fd(fd1)?))
-    } else {
-        Err(io::Error::last_os_error())
-    }
+    cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?;
+
+    let fd0 = FileDesc::new(fds[0]);
+    let fd1 = FileDesc::new(fds[1]);
+    fd0.set_cloexec()?;
+    fd1.set_cloexec()?;
+    Ok((AnonPipe(fd0), AnonPipe(fd1)))
 }
 
 impl AnonPipe {
-    pub fn from_fd(fd: FileDesc) -> io::Result<AnonPipe> {
-        fd.set_cloexec()?;
-        Ok(AnonPipe(fd))
-    }
-
     pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
         self.0.read(buf)
     }
diff --git a/src/libstd/sys/windows/backtrace.rs b/src/libstd/sys/windows/backtrace.rs
index 82a44c1c110..94aaf439f3d 100644
--- a/src/libstd/sys/windows/backtrace.rs
+++ b/src/libstd/sys/windows/backtrace.rs
@@ -51,6 +51,10 @@ mod printing;
 #[path = "printing/gnu.rs"]
 mod printing;
 
+#[cfg(target_env = "gnu")]
+#[path = "backtrace_gnu.rs"]
+pub mod gnu;
+
 type SymInitializeFn =
     unsafe extern "system" fn(c::HANDLE, *mut c_void,
                               c::BOOL) -> c::BOOL;
diff --git a/src/libstd/sys/windows/backtrace_gnu.rs b/src/libstd/sys/windows/backtrace_gnu.rs
new file mode 100644
index 00000000000..f0d29dd4178
--- /dev/null
+++ b/src/libstd/sys/windows/backtrace_gnu.rs
@@ -0,0 +1,62 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use io;
+use sys::c;
+use libc::c_char;
+use path::PathBuf;
+use fs::{OpenOptions, File};
+use sys::ext::fs::OpenOptionsExt;
+use sys::handle::Handle;
+use super::super::{fill_utf16_buf, os2path, to_u16s, wide_char_to_multi_byte};
+
+fn query_full_process_image_name() -> io::Result<PathBuf> {
+    unsafe {
+        let process_handle = Handle::new(c::OpenProcess(c::PROCESS_QUERY_INFORMATION,
+                                                        c::FALSE,
+                                                        c::GetCurrentProcessId()));
+        fill_utf16_buf(|buf, mut sz| {
+            if c::QueryFullProcessImageNameW(process_handle.raw(), 0, buf, &mut sz) == 0 {
+                0
+            } else {
+                sz
+            }
+        }, os2path)
+    }
+}
+
+fn lock_and_get_executable_filename() -> io::Result<(PathBuf, File)> {
+    // We query the current image name, open the file without FILE_SHARE_DELETE so it
+    // can't be moved and then get the current image name again. If the names are the
+    // same than we have successfully locked the file
+    let image_name1 = query_full_process_image_name()?;
+    let file = OpenOptions::new()
+                .read(true)
+                .share_mode(c::FILE_SHARE_READ | c::FILE_SHARE_WRITE)
+                .open(&image_name1)?;
+    let image_name2 = query_full_process_image_name()?;
+
+    if image_name1 != image_name2 {
+        return Err(io::Error::new(io::ErrorKind::Other,
+                                  "executable moved while trying to lock it"));
+    }
+
+    Ok((image_name1, file))
+}
+
+// Get the executable filename for libbacktrace
+// This returns the path in the ANSI code page and a File which should remain open
+// for as long as the path should remain valid
+pub fn get_executable_filename() -> io::Result<(Vec<c_char>, File)> {
+    let (executable, file) = lock_and_get_executable_filename()?;
+    let u16_executable = to_u16s(executable.into_os_string())?;
+    Ok((wide_char_to_multi_byte(c::CP_ACP, c::WC_NO_BEST_FIT_CHARS,
+                                &u16_executable, true)?, file))
+}
diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs
index dc7b2fc9a6b..1b29bf73c7a 100644
--- a/src/libstd/sys/windows/c.rs
+++ b/src/libstd/sys/windows/c.rs
@@ -69,6 +69,7 @@ pub type LPWCH = *mut WCHAR;
 pub type LPWIN32_FIND_DATAW = *mut WIN32_FIND_DATAW;
 pub type LPWSADATA = *mut WSADATA;
 pub type LPWSAPROTOCOL_INFO = *mut WSAPROTOCOL_INFO;
+pub type LPSTR = *mut CHAR;
 pub type LPWSTR = *mut WCHAR;
 pub type LPFILETIME = *mut FILETIME;
 
@@ -973,6 +974,14 @@ extern "system" {
     pub fn DeleteFileW(lpPathName: LPCWSTR) -> BOOL;
     pub fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: LPWSTR) -> DWORD;
     pub fn SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL;
+    pub fn WideCharToMultiByte(CodePage: UINT,
+                               dwFlags: DWORD,
+                               lpWideCharStr: LPCWSTR,
+                               cchWideChar: c_int,
+                               lpMultiByteStr: LPSTR,
+                               cbMultiByte: c_int,
+                               lpDefaultChar: LPCSTR,
+                               lpUsedDefaultChar: LPBOOL) -> c_int;
 
     pub fn closesocket(socket: SOCKET) -> c_int;
     pub fn recv(socket: SOCKET, buf: *mut c_void, len: c_int,
@@ -1178,3 +1187,34 @@ compat_fn! {
         panic!("rwlocks not available")
     }
 }
+
+#[cfg(target_env = "gnu")]
+mod gnu {
+    use super::*;
+
+    pub const PROCESS_QUERY_INFORMATION: DWORD = 0x0400;
+
+    pub const CP_ACP: UINT = 0;
+
+    pub const WC_NO_BEST_FIT_CHARS: DWORD = 0x00000400;
+
+    extern "system" {
+        pub fn OpenProcess(dwDesiredAccess: DWORD,
+                           bInheritHandle: BOOL,
+                           dwProcessId: DWORD) -> HANDLE;
+    }
+
+    compat_fn! {
+        kernel32:
+
+        pub fn QueryFullProcessImageNameW(_hProcess: HANDLE,
+                                          _dwFlags: DWORD,
+                                          _lpExeName: LPWSTR,
+                                          _lpdwSize: LPDWORD) -> BOOL {
+            SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0
+        }
+    }
+}
+
+#[cfg(target_env = "gnu")]
+pub use self::gnu::*;
diff --git a/src/libstd/sys/windows/ext/process.rs b/src/libstd/sys/windows/ext/process.rs
index 0a3221aeae6..1419a4af427 100644
--- a/src/libstd/sys/windows/ext/process.rs
+++ b/src/libstd/sys/windows/ext/process.rs
@@ -99,17 +99,17 @@ impl ExitStatusExt for process::ExitStatus {
 }
 
 /// Windows-specific extensions to the `std::process::Command` builder
-#[unstable(feature = "windows_process_extensions", issue = "37827")]
+#[stable(feature = "windows_process_extensions", since = "1.16.0")]
 pub trait CommandExt {
     /// Sets the [process creation flags][1] to be passed to `CreateProcess`.
     ///
     /// These will always be ORed with `CREATE_UNICODE_ENVIRONMENT`.
     /// [1]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx
-    #[unstable(feature = "windows_process_extensions", issue = "37827")]
+    #[stable(feature = "windows_process_extensions", since = "1.16.0")]
     fn creation_flags(&mut self, flags: u32) -> &mut process::Command;
 }
 
-#[unstable(feature = "windows_process_extensions", issue = "37827")]
+#[stable(feature = "windows_process_extensions", since = "1.16.0")]
 impl CommandExt for process::Command {
     fn creation_flags(&mut self, flags: u32) -> &mut process::Command {
         self.as_inner_mut().creation_flags(flags);
diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs
index defc41c5f46..4424c6c6136 100644
--- a/src/libstd/sys/windows/mod.rs
+++ b/src/libstd/sys/windows/mod.rs
@@ -10,6 +10,7 @@
 
 #![allow(missing_docs, bad_style)]
 
+use ptr;
 use ffi::{OsStr, OsString};
 use io::{self, ErrorKind};
 use os::windows::ffi::{OsStrExt, OsStringExt};
@@ -171,6 +172,52 @@ fn os2path(s: &[u16]) -> PathBuf {
     PathBuf::from(OsString::from_wide(s))
 }
 
+#[allow(dead_code)] // Only used in backtrace::gnu::get_executable_filename()
+fn wide_char_to_multi_byte(code_page: u32,
+                           flags: u32,
+                           s: &[u16],
+                           no_default_char: bool)
+                           -> io::Result<Vec<i8>> {
+    unsafe {
+        let mut size = c::WideCharToMultiByte(code_page,
+                                              flags,
+                                              s.as_ptr(),
+                                              s.len() as i32,
+                                              ptr::null_mut(),
+                                              0,
+                                              ptr::null(),
+                                              ptr::null_mut());
+        if size == 0 {
+            return Err(io::Error::last_os_error());
+        }
+
+        let mut buf = Vec::with_capacity(size as usize);
+        buf.set_len(size as usize);
+
+        let mut used_default_char = c::FALSE;
+        size = c::WideCharToMultiByte(code_page,
+                                      flags,
+                                      s.as_ptr(),
+                                      s.len() as i32,
+                                      buf.as_mut_ptr(),
+                                      buf.len() as i32,
+                                      ptr::null(),
+                                      if no_default_char { &mut used_default_char }
+                                      else { ptr::null_mut() });
+        if size == 0 {
+            return Err(io::Error::last_os_error());
+        }
+        if no_default_char && used_default_char == c::TRUE {
+            return Err(io::Error::new(io::ErrorKind::InvalidData,
+                                      "string cannot be converted to requested code page"));
+        }
+
+        buf.set_len(size as usize);
+
+        Ok(buf)
+    }
+}
+
 pub fn truncate_utf16_at_nul<'a>(v: &'a [u16]) -> &'a [u16] {
     match v.iter().position(|c| *c == 0) {
         // don't include the 0
diff --git a/src/libstd/sys_common/gnu/libbacktrace.rs b/src/libstd/sys_common/gnu/libbacktrace.rs
index b5802afc109..d464a13ad1d 100644
--- a/src/libstd/sys_common/gnu/libbacktrace.rs
+++ b/src/libstd/sys_common/gnu/libbacktrace.rs
@@ -16,6 +16,7 @@ use sys_common::backtrace::{output, output_fileline};
 pub fn print(w: &mut Write, idx: isize, addr: *mut libc::c_void,
              symaddr: *mut libc::c_void) -> io::Result<()> {
     use ffi::CStr;
+    use mem;
     use ptr;
 
     ////////////////////////////////////////////////////////////////////////
@@ -124,7 +125,21 @@ pub fn print(w: &mut Write, idx: isize, addr: *mut libc::c_void,
     unsafe fn init_state() -> *mut backtrace_state {
         static mut STATE: *mut backtrace_state = ptr::null_mut();
         if !STATE.is_null() { return STATE }
-        STATE = backtrace_create_state(ptr::null(), 0, error_cb,
+
+        let filename = match ::sys::backtrace::gnu::get_executable_filename() {
+            Ok((filename, file)) => {
+                // filename is purposely leaked here since libbacktrace requires
+                // it to stay allocated permanently, file is also leaked so that
+                // the file stays locked
+                let filename_ptr = filename.as_ptr();
+                mem::forget(filename);
+                mem::forget(file);
+                filename_ptr
+            },
+            Err(_) => ptr::null(),
+        };
+
+        STATE = backtrace_create_state(filename, 0, error_cb,
                                        ptr::null_mut());
         STATE
     }
diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs
index 07a9b4bed99..8789006436c 100644
--- a/src/libstd/thread/mod.rs
+++ b/src/libstd/thread/mod.rs
@@ -391,7 +391,7 @@ impl Builder {
 /// [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html
 /// [`join`]: ../../std/thread/struct.JoinHandle.html#method.join
 /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
-/// [`panic!`]: ../../std/macro.panic.html
+/// [`panic`]: ../../std/macro.panic.html
 /// [`Builder::spawn`]: ../../std/thread/struct.Builder.html#method.spawn
 ///
 /// # Examples
@@ -974,7 +974,7 @@ impl<T> JoinHandle<T> {
     /// to [`panic`].
     ///
     /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
-    /// [`panic!`]: ../../std/macro.panic.html
+    /// [`panic`]: ../../std/macro.panic.html
     ///
     /// # Examples
     ///
diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs
index 2c4e2bbff93..af7eaeb3106 100644
--- a/src/libstd/time/duration.rs
+++ b/src/libstd/time/duration.rs
@@ -154,14 +154,12 @@ impl Duration {
     /// Basic usage:
     ///
     /// ```
-    /// #![feature(duration_checked_ops)]
-    ///
     /// use std::time::Duration;
     ///
     /// assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), Some(Duration::new(0, 1)));
     /// assert_eq!(Duration::new(1, 0).checked_add(Duration::new(std::u64::MAX, 0)), None);
     /// ```
-    #[unstable(feature = "duration_checked_ops", issue = "35774")]
+    #[stable(feature = "duration_checked_ops", since = "1.16.0")]
     #[inline]
     pub fn checked_add(self, rhs: Duration) -> Option<Duration> {
         if let Some(mut secs) = self.secs.checked_add(rhs.secs) {
@@ -194,14 +192,12 @@ impl Duration {
     /// Basic usage:
     ///
     /// ```
-    /// #![feature(duration_checked_ops)]
-    ///
     /// use std::time::Duration;
     ///
     /// assert_eq!(Duration::new(0, 1).checked_sub(Duration::new(0, 0)), Some(Duration::new(0, 1)));
     /// assert_eq!(Duration::new(0, 0).checked_sub(Duration::new(0, 1)), None);
     /// ```
-    #[unstable(feature = "duration_checked_ops", issue = "35774")]
+    #[stable(feature = "duration_checked_ops", since = "1.16.0")]
     #[inline]
     pub fn checked_sub(self, rhs: Duration) -> Option<Duration> {
         if let Some(mut secs) = self.secs.checked_sub(rhs.secs) {
@@ -232,14 +228,12 @@ impl Duration {
     /// Basic usage:
     ///
     /// ```
-    /// #![feature(duration_checked_ops)]
-    ///
     /// use std::time::Duration;
     ///
     /// assert_eq!(Duration::new(0, 500_000_001).checked_mul(2), Some(Duration::new(1, 2)));
     /// assert_eq!(Duration::new(std::u64::MAX - 1, 0).checked_mul(2), None);
     /// ```
-    #[unstable(feature = "duration_checked_ops", issue = "35774")]
+    #[stable(feature = "duration_checked_ops", since = "1.16.0")]
     #[inline]
     pub fn checked_mul(self, rhs: u32) -> Option<Duration> {
         // Multiply nanoseconds as u64, because it cannot overflow that way.
@@ -269,15 +263,13 @@ impl Duration {
     /// Basic usage:
     ///
     /// ```
-    /// #![feature(duration_checked_ops)]
-    ///
     /// use std::time::Duration;
     ///
     /// assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0)));
     /// assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000)));
     /// assert_eq!(Duration::new(2, 0).checked_div(0), None);
     /// ```
-    #[unstable(feature = "duration_checked_ops", issue = "35774")]
+    #[stable(feature = "duration_checked_ops", since = "1.16.0")]
     #[inline]
     pub fn checked_div(self, rhs: u32) -> Option<Duration> {
         if rhs != 0 {