about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-08-14 15:27:15 -0700
committerGitHub <noreply@github.com>2016-08-14 15:27:15 -0700
commit13ff307f07327843348c0fb7476c4de77f95f89f (patch)
tree714f14faa5bb09f1e0c072e1cbfa15740ee7cbf5 /src/libstd
parent1d5b758bab979b1db723bcc97ecd8398127bd8bc (diff)
parentbcee2edc54d04a2fcf5ba9e4a4a095bcf9be2bfc (diff)
downloadrust-13ff307f07327843348c0fb7476c4de77f95f89f.tar.gz
rust-13ff307f07327843348c0fb7476c4de77f95f89f.zip
Auto merge of #35666 - eddyb:rollup, r=eddyb
Rollup of 30 pull requests

- Successful merges: #34941, #35392, #35444, #35447, #35491, #35533, #35539, #35558, #35573, #35574, #35577, #35586, #35588, #35594, #35596, #35597, #35598, #35606, #35611, #35615, #35616, #35620, #35622, #35640, #35643, #35644, #35646, #35647, #35648, #35661
- Failed merges: #35395, #35415
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/env.rs4
-rw-r--r--src/libstd/panicking.rs104
-rw-r--r--src/libstd/sys/unix/mod.rs4
-rw-r--r--src/libstd/sys/unix/os.rs6
-rw-r--r--src/libstd/sys/unix/thread.rs7
5 files changed, 79 insertions, 46 deletions
diff --git a/src/libstd/env.rs b/src/libstd/env.rs
index d6d62ce79d4..753411991ab 100644
--- a/src/libstd/env.rs
+++ b/src/libstd/env.rs
@@ -526,10 +526,10 @@ pub fn temp_dir() -> PathBuf {
 /// Ok("/home/alex/bar")
 /// ```
 ///
-/// This sort of behavior has been known to [lead to privledge escalation] when
+/// This sort of behavior has been known to [lead to privilege escalation] when
 /// used incorrectly, for example.
 ///
-/// [lead to privledge escalation]: http://securityvulns.com/Wdocument183.html
+/// [lead to privilege escalation]: http://securityvulns.com/Wdocument183.html
 ///
 /// # Examples
 ///
diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs
index 8c1567939fb..5961fd59699 100644
--- a/src/libstd/panicking.rs
+++ b/src/libstd/panicking.rs
@@ -25,9 +25,10 @@ use cell::RefCell;
 use fmt;
 use intrinsics;
 use mem;
+use ptr;
 use raw;
-use sys_common::rwlock::RWLock;
 use sys::stdio::Stderr;
+use sys_common::rwlock::RWLock;
 use sys_common::thread_info;
 use sys_common::util;
 use thread;
@@ -255,45 +256,76 @@ 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: FnOnce() -> R>(f: F) -> Result<R, Box<Any + Send>> {
-    let mut slot = None;
-    let mut f = Some(f);
-    let ret;
-
-    {
-        let mut to_run = || {
-            slot = Some(f.take().unwrap()());
-        };
-        let fnptr = get_call(&mut to_run);
-        let dataptr = &mut to_run as *mut _ as *mut u8;
-        let mut any_data = 0;
-        let mut any_vtable = 0;
-        let fnptr = mem::transmute::<fn(&mut _), fn(*mut u8)>(fnptr);
-        let r = __rust_maybe_catch_panic(fnptr,
-                                         dataptr,
-                                         &mut any_data,
-                                         &mut any_vtable);
-        if r == 0 {
-            ret = Ok(());
-        } else {
-            update_panic_count(-1);
-            ret = Err(mem::transmute(raw::TraitObject {
-                data: any_data as *mut _,
-                vtable: any_vtable as *mut _,
-            }));
-        }
+    struct Data<F, R> {
+        f: F,
+        r: R,
     }
 
-    debug_assert!(update_panic_count(0) == 0);
-    return ret.map(|()| {
-        slot.take().unwrap()
-    });
+    // We do some sketchy operations with ownership here for the sake of
+    // performance. The `Data` structure is never actually fully valid, but
+    // instead it always contains at least one uninitialized field. We can only
+    // pass pointers down to `__rust_maybe_catch_panic` (can't pass objects by
+    // value), so we do all the ownership tracking here manully.
+    //
+    // Note that this is all invalid if any of these functions unwind, but the
+    // whole point of this function is to prevent that! As a result we go
+    // through a transition where:
+    //
+    // * First, only the closure we're going to call is initialized. The return
+    //   value is uninitialized.
+    // * When we make the function call, the `do_call` function below, we take
+    //   ownership of the function pointer, replacing it with uninitialized
+    //   data. At this point the `Data` structure is entirely uninitialized, but
+    //   it won't drop due to an unwind because it's owned on the other side of
+    //   the catch panic.
+    // * If the closure successfully returns, we write the return value into the
+    //   data's return slot. Note that `ptr::write` is used as it's overwriting
+    //   uninitialized data.
+    // * Finally, when we come back out of the `__rust_maybe_catch_panic` we're
+    //   in one of two states:
+    //
+    //      1. The closure didn't panic, in which case the return value was
+    //         filled in. We have to be careful to `forget` the closure,
+    //         however, as ownership was passed to the `do_call` function.
+    //      2. The closure panicked, in which case the return value wasn't
+    //         filled in. In this case the entire `data` structure is invalid,
+    //         so we forget the entire thing.
+    //
+    // Once we stack all that together we should have the "most efficient'
+    // method of calling a catch panic whilst juggling ownership.
+    let mut any_data = 0;
+    let mut any_vtable = 0;
+    let mut data = Data {
+        f: f,
+        r: mem::uninitialized(),
+    };
 
-    fn get_call<F: FnMut()>(_: &mut F) -> fn(&mut F) {
-        call
-    }
+    let r = __rust_maybe_catch_panic(do_call::<F, R>,
+                                     &mut data as *mut _ as *mut u8,
+                                     &mut any_data,
+                                     &mut any_vtable);
+
+    return if r == 0 {
+        let Data { f, r } = data;
+        mem::forget(f);
+        debug_assert!(update_panic_count(0) == 0);
+        Ok(r)
+    } else {
+        mem::forget(data);
+        update_panic_count(-1);
+        debug_assert!(update_panic_count(0) == 0);
+        Err(mem::transmute(raw::TraitObject {
+            data: any_data as *mut _,
+            vtable: any_vtable as *mut _,
+        }))
+    };
 
-    fn call<F: FnMut()>(f: &mut F) {
-        f()
+    fn do_call<F: FnOnce() -> R, R>(data: *mut u8) {
+        unsafe {
+            let data = data as *mut Data<F, R>;
+            let f = ptr::read(&mut (*data).f);
+            ptr::write(&mut (*data).r, f());
+        }
     }
 }
 
diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs
index 1c25c8f77c1..23687e10e47 100644
--- a/src/libstd/sys/unix/mod.rs
+++ b/src/libstd/sys/unix/mod.rs
@@ -83,11 +83,11 @@ pub fn init() {
         }
     }
 
-    #[cfg(not(target_os = "nacl"))]
+    #[cfg(not(any(target_os = "nacl", target_os = "emscripten")))]
     unsafe fn reset_sigpipe() {
         assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != !0);
     }
-    #[cfg(target_os = "nacl")]
+    #[cfg(any(target_os = "nacl", target_os = "emscripten"))]
     unsafe fn reset_sigpipe() {}
 }
 
diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs
index 9c57f25dfcc..c29e87f91c9 100644
--- a/src/libstd/sys/unix/os.rs
+++ b/src/libstd/sys/unix/os.rs
@@ -551,11 +551,13 @@ pub fn home_dir() -> Option<PathBuf> {
 
     #[cfg(any(target_os = "android",
               target_os = "ios",
-              target_os = "nacl"))]
+              target_os = "nacl",
+              target_os = "emscripten"))]
     unsafe fn fallback() -> Option<OsString> { None }
     #[cfg(not(any(target_os = "android",
                   target_os = "ios",
-                  target_os = "nacl")))]
+                  target_os = "nacl",
+                  target_os = "emscripten")))]
     unsafe fn fallback() -> Option<OsString> {
         #[cfg(not(target_os = "solaris"))]
         unsafe fn getpwduid_r(me: libc::uid_t, passwd: &mut libc::passwd,
diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs
index 1061ca87f64..75e10d25853 100644
--- a/src/libstd/sys/unix/thread.rs
+++ b/src/libstd/sys/unix/thread.rs
@@ -81,8 +81,7 @@ impl Thread {
     }
 
     #[cfg(any(target_os = "linux",
-              target_os = "android",
-              target_os = "emscripten"))]
+              target_os = "android"))]
     pub fn set_name(name: &CStr) {
         const PR_SET_NAME: libc::c_int = 15;
         // pthread wrapper only appeared in glibc 2.12, so we use syscall
@@ -118,9 +117,9 @@ impl Thread {
                                      name.as_ptr() as *mut libc::c_void);
         }
     }
-    #[cfg(any(target_env = "newlib", target_os = "solaris"))]
+    #[cfg(any(target_env = "newlib", target_os = "solaris", target_os = "emscripten"))]
     pub fn set_name(_name: &CStr) {
-        // Newlib and Illumos has no way to set a thread name.
+        // Newlib, Illumos and Emscripten have no way to set a thread name.
     }
 
     pub fn sleep(dur: Duration) {