diff options
| author | bors <bors@rust-lang.org> | 2016-08-14 15:27:15 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2016-08-14 15:27:15 -0700 |
| commit | 13ff307f07327843348c0fb7476c4de77f95f89f (patch) | |
| tree | 714f14faa5bb09f1e0c072e1cbfa15740ee7cbf5 /src/libstd | |
| parent | 1d5b758bab979b1db723bcc97ecd8398127bd8bc (diff) | |
| parent | bcee2edc54d04a2fcf5ba9e4a4a095bcf9be2bfc (diff) | |
| download | rust-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.rs | 4 | ||||
| -rw-r--r-- | src/libstd/panicking.rs | 104 | ||||
| -rw-r--r-- | src/libstd/sys/unix/mod.rs | 4 | ||||
| -rw-r--r-- | src/libstd/sys/unix/os.rs | 6 | ||||
| -rw-r--r-- | src/libstd/sys/unix/thread.rs | 7 |
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) { |
