about summary refs log tree commit diff
path: root/src/libstd/sys_common
diff options
context:
space:
mode:
authorphosphorus <steepout@qq.com>2019-08-19 00:34:02 -0500
committerGitHub <noreply@github.com>2019-08-19 00:34:02 -0500
commit92f08b78a12ff119af853cb2bf58468208ea6a90 (patch)
treeb4636f43c056de11dd69130ce47039343a9f52c5 /src/libstd/sys_common
parent963184bbb670c1ffa97fc28a98cd5e8473118859 (diff)
parenta807902dd6b4222179776c3f3c33da8dafdd4da1 (diff)
downloadrust-92f08b78a12ff119af853cb2bf58468208ea6a90.tar.gz
rust-92f08b78a12ff119af853cb2bf58468208ea6a90.zip
Merge pull request #1 from rust-lang/master
Pull from newest repo
Diffstat (limited to 'src/libstd/sys_common')
-rw-r--r--src/libstd/sys_common/alloc.rs3
-rw-r--r--src/libstd/sys_common/backtrace.rs304
-rw-r--r--src/libstd/sys_common/gnu/libbacktrace.rs175
-rw-r--r--src/libstd/sys_common/gnu/mod.rs5
-rw-r--r--src/libstd/sys_common/io.rs2
-rw-r--r--src/libstd/sys_common/mod.rs9
-rw-r--r--src/libstd/sys_common/os_str_bytes.rs6
7 files changed, 163 insertions, 341 deletions
diff --git a/src/libstd/sys_common/alloc.rs b/src/libstd/sys_common/alloc.rs
index 978a70bee09..1cfc7ed17f2 100644
--- a/src/libstd/sys_common/alloc.rs
+++ b/src/libstd/sys_common/alloc.rs
@@ -12,7 +12,8 @@ use crate::ptr;
               target_arch = "powerpc",
               target_arch = "powerpc64",
               target_arch = "asmjs",
-              target_arch = "wasm32")))]
+              target_arch = "wasm32",
+              target_arch = "hexagon")))]
 pub const MIN_ALIGN: usize = 8;
 #[cfg(all(any(target_arch = "x86_64",
               target_arch = "aarch64",
diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs
index 8d8d8169b43..bf37ff7ddbd 100644
--- a/src/libstd/sys_common/backtrace.rs
+++ b/src/libstd/sys_common/backtrace.rs
@@ -2,40 +2,17 @@
 /// supported platforms.
 
 use crate::env;
-use crate::io::prelude::*;
 use crate::io;
+use crate::io::prelude::*;
+use crate::mem;
 use crate::path::{self, Path};
 use crate::ptr;
-use crate::str;
 use crate::sync::atomic::{self, Ordering};
 use crate::sys::mutex::Mutex;
 
-use rustc_demangle::demangle;
-
-pub use crate::sys::backtrace::{
-    unwind_backtrace,
-    resolve_symname,
-    foreach_symbol_fileline,
-    BacktraceContext
-};
-
-#[cfg(target_pointer_width = "64")]
-pub const HEX_WIDTH: usize = 18;
-
-#[cfg(target_pointer_width = "32")]
-pub const HEX_WIDTH: usize = 10;
-
-/// Represents an item in the backtrace list. See `unwind_backtrace` for how
-/// it is created.
-#[derive(Debug, Copy, Clone)]
-pub struct Frame {
-    /// Exact address of the call that failed.
-    pub exact_position: *const u8,
-    /// Address of the enclosing function.
-    pub symbol_addr: *const u8,
-    /// Which inlined function is this frame referring to
-    pub inline_context: u32,
-}
+use backtrace::{BytesOrWideString, Frame, Symbol};
+
+pub const HEX_WIDTH: usize = 2 + 2 * mem::size_of::<usize>();
 
 /// Max number of frames to print.
 const MAX_NB_FRAMES: usize = 100;
@@ -49,7 +26,7 @@ pub fn print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> {
     // test mode immediately return here to optimize away any references to the
     // libbacktrace symbols
     if cfg!(test) {
-        return Ok(())
+        return Ok(());
     }
 
     // Use a lock to prevent mixed output in multithreading context.
@@ -63,75 +40,39 @@ pub fn print(w: &mut dyn 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(),
-        inline_context: 0,
-    }; MAX_NB_FRAMES];
-    let (nb_frames, context) = unwind_backtrace(&mut frames)?;
-    let (skipped_before, skipped_after) =
-        filter_frames(&frames[..nb_frames], format, &context);
-    if skipped_before + skipped_after > 0 {
-        writeln!(w, "note: Some details are omitted, \
-                     run with `RUST_BACKTRACE=full` for a verbose backtrace.")?;
-    }
     writeln!(w, "stack backtrace:")?;
 
-    let filtered_frames = &frames[..nb_frames - skipped_after];
-    for (index, frame) in filtered_frames.iter().skip(skipped_before).enumerate() {
-        resolve_symname(*frame, |symname| {
-            output(w, index, *frame, symname, format)
-        }, &context)?;
-        let has_more_filenames = foreach_symbol_fileline(*frame, |file, line| {
-            output_fileline(w, file, line, format)
-        }, &context)?;
-        if has_more_filenames {
-            w.write_all(b" <... and possibly more>")?;
-        }
-    }
-
-    Ok(())
-}
-
-/// Returns a number of frames to remove at the beginning and at the end of the
-/// backtrace, according to the backtrace format.
-fn filter_frames(frames: &[Frame],
-                 format: PrintFormat,
-                 context: &BacktraceContext) -> (usize, usize)
-{
-    if format == PrintFormat::Full {
-        return (0, 0);
-    }
-
-    let skipped_before = 0;
-
-    let skipped_after = frames.len() - frames.iter().position(|frame| {
-        let mut is_marker = false;
-        let _ = resolve_symname(*frame, |symname| {
-            if let Some(mangled_symbol_name) = symname {
-                // Use grep to find the concerned functions
-                if mangled_symbol_name.contains("__rust_begin_short_backtrace") {
-                    is_marker = true;
-                }
+    let mut printer = Printer::new(format, w);
+    unsafe {
+        backtrace::trace_unsynchronized(|frame| {
+            let mut hit = false;
+            backtrace::resolve_frame_unsynchronized(frame, |symbol| {
+                hit = true;
+                printer.output(frame, Some(symbol));
+            });
+            if !hit {
+                printer.output(frame, None);
             }
-            Ok(())
-        }, context);
-        is_marker
-    }).unwrap_or(frames.len());
-
-    if skipped_before + skipped_after >= frames.len() {
-        // Avoid showing completely empty backtraces
-        return (0, 0);
+            !printer.done
+        });
     }
-
-    (skipped_before, skipped_after)
+    if printer.skipped {
+        writeln!(
+            w,
+            "note: Some details are omitted, \
+             run with `RUST_BACKTRACE=full` for a verbose backtrace."
+        )?;
+    }
+    Ok(())
 }
 
-
 /// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`.
 #[inline(never)]
 pub fn __rust_begin_short_backtrace<F, T>(f: F) -> T
-    where F: FnOnce() -> T, F: Send, T: Send
+where
+    F: FnOnce() -> T,
+    F: Send,
+    T: Send,
 {
     f()
 }
@@ -156,7 +97,7 @@ pub fn log_enabled() -> Option<PrintFormat> {
         _ => return Some(PrintFormat::Full),
     }
 
-    let val = env::var_os("RUST_BACKTRACE").and_then(|x|
+    let val = env::var_os("RUST_BACKTRACE").and_then(|x| {
         if &x == "0" {
             None
         } else if &x == "full" {
@@ -164,80 +105,141 @@ pub fn log_enabled() -> Option<PrintFormat> {
         } else {
             Some(PrintFormat::Short)
         }
+    });
+    ENABLED.store(
+        match val {
+            Some(v) => v as isize,
+            None => 1,
+        },
+        Ordering::SeqCst,
     );
-    ENABLED.store(match val {
-        Some(v) => v as isize,
-        None => 1,
-    }, Ordering::SeqCst);
     val
 }
 
-/// Prints the symbol of the backtrace frame.
-///
-/// These output functions should now be used everywhere to ensure consistency.
-/// You may want to also use `output_fileline`.
-fn output(w: &mut dyn Write, idx: usize, frame: Frame,
-              s: Option<&str>, format: PrintFormat) -> io::Result<()> {
-    // Remove the `17: 0x0 - <unknown>` line.
-    if format == PrintFormat::Short && frame.exact_position == ptr::null() {
-        return Ok(());
+struct Printer<'a, 'b> {
+    format: PrintFormat,
+    done: bool,
+    skipped: bool,
+    idx: usize,
+    out: &'a mut (dyn Write + 'b),
+}
+
+impl<'a, 'b> Printer<'a, 'b> {
+    fn new(format: PrintFormat, out: &'a mut (dyn Write + 'b)) -> Printer<'a, 'b> {
+        Printer { format, done: false, skipped: false, idx: 0, out }
     }
-    match format {
-        PrintFormat::Full => write!(w,
-                                    "  {:2}: {:2$?} - ",
-                                    idx,
-                                    frame.exact_position,
-                                    HEX_WIDTH)?,
-        PrintFormat::Short => write!(w, "  {:2}: ", idx)?,
+
+    /// Prints the symbol of the backtrace frame.
+    ///
+    /// These output functions should now be used everywhere to ensure consistency.
+    /// You may want to also use `output_fileline`.
+    fn output(&mut self, frame: &Frame, symbol: Option<&Symbol>) {
+        if self.idx > MAX_NB_FRAMES {
+            self.done = true;
+            self.skipped = true;
+            return;
+        }
+        if self._output(frame, symbol).is_err() {
+            self.done = true;
+        }
+        self.idx += 1;
     }
-    match s {
-        Some(string) => {
-            let symbol = demangle(string);
-            match format {
-                PrintFormat::Full => write!(w, "{}", symbol)?,
-                // strip the trailing hash if short mode
-                PrintFormat::Short => write!(w, "{:#}", symbol)?,
+
+    fn _output(&mut self, frame: &Frame, symbol: Option<&Symbol>) -> io::Result<()> {
+        if self.format == PrintFormat::Short {
+            if let Some(sym) = symbol.and_then(|s| s.name()).and_then(|s| s.as_str()) {
+                if sym.contains("__rust_begin_short_backtrace") {
+                    self.skipped = true;
+                    self.done = true;
+                    return Ok(());
+                }
+            }
+
+            // Remove the `17: 0x0 - <unknown>` line.
+            if self.format == PrintFormat::Short && frame.ip() == ptr::null_mut() {
+                self.skipped = true;
+                return Ok(());
             }
         }
-        None => w.write_all(b"<unknown>")?,
-    }
-    w.write_all(b"\n")
-}
 
-/// Prints the filename and line number of the backtrace frame.
-///
-/// See also `output`.
-#[allow(dead_code)]
-fn output_fileline(w: &mut dyn Write,
-                   file: &[u8],
-                   line: u32,
-                   format: PrintFormat) -> io::Result<()> {
-    // prior line: "  ##: {:2$} - func"
-    w.write_all(b"")?;
-    match format {
-        PrintFormat::Full => write!(w,
-                                    "           {:1$}",
-                                    "",
-                                    HEX_WIDTH)?,
-        PrintFormat::Short => write!(w, "           ")?,
-    }
+        match self.format {
+            PrintFormat::Full => {
+                write!(self.out, "  {:2}: {:2$?} - ", self.idx, frame.ip(), HEX_WIDTH)?
+            }
+            PrintFormat::Short => write!(self.out, "  {:2}: ", self.idx)?,
+        }
 
-    let file = str::from_utf8(file).unwrap_or("<unknown>");
-    let file_path = Path::new(file);
-    let mut already_printed = false;
-    if format == PrintFormat::Short && file_path.is_absolute() {
-        if let Ok(cwd) = env::current_dir() {
-            if let Ok(stripped) = file_path.strip_prefix(&cwd) {
-                if let Some(s) = stripped.to_str() {
-                    write!(w, "  at .{}{}:{}", path::MAIN_SEPARATOR, s, line)?;
-                    already_printed = true;
+        match symbol.and_then(|s| s.name()) {
+            Some(symbol) => {
+                match self.format {
+                    PrintFormat::Full => write!(self.out, "{}", symbol)?,
+                    // Strip the trailing hash if short mode.
+                    PrintFormat::Short => write!(self.out, "{:#}", symbol)?,
                 }
             }
+            None => self.out.write_all(b"<unknown>")?,
         }
-    }
-    if !already_printed {
-        write!(w, "  at {}:{}", file, line)?;
+        self.out.write_all(b"\n")?;
+        if let Some(sym) = symbol {
+            self.output_fileline(sym)?;
+        }
+        Ok(())
     }
 
-    w.write_all(b"\n")
+    /// Prints the filename and line number of the backtrace frame.
+    ///
+    /// See also `output`.
+    fn output_fileline(&mut self, symbol: &Symbol) -> io::Result<()> {
+        #[cfg(windows)]
+        let path_buf;
+        let file = match symbol.filename_raw() {
+            #[cfg(unix)]
+            Some(BytesOrWideString::Bytes(bytes)) => {
+                use crate::os::unix::prelude::*;
+                Path::new(crate::ffi::OsStr::from_bytes(bytes))
+            }
+            #[cfg(not(unix))]
+            Some(BytesOrWideString::Bytes(bytes)) => {
+                Path::new(crate::str::from_utf8(bytes).unwrap_or("<unknown>"))
+            }
+            #[cfg(windows)]
+            Some(BytesOrWideString::Wide(wide)) => {
+                use crate::os::windows::prelude::*;
+                path_buf = crate::ffi::OsString::from_wide(wide);
+                Path::new(&path_buf)
+            }
+            #[cfg(not(windows))]
+            Some(BytesOrWideString::Wide(_wide)) => {
+                Path::new("<unknown>")
+            }
+            None => return Ok(()),
+        };
+        let line = match symbol.lineno() {
+            Some(line) => line,
+            None => return Ok(()),
+        };
+        // prior line: "  ##: {:2$} - func"
+        self.out.write_all(b"")?;
+        match self.format {
+            PrintFormat::Full => write!(self.out, "           {:1$}", "", HEX_WIDTH)?,
+            PrintFormat::Short => write!(self.out, "           ")?,
+        }
+
+        let mut already_printed = false;
+        if self.format == PrintFormat::Short && file.is_absolute() {
+            if let Ok(cwd) = env::current_dir() {
+                if let Ok(stripped) = file.strip_prefix(&cwd) {
+                    if let Some(s) = stripped.to_str() {
+                        write!(self.out, "  at .{}{}:{}", path::MAIN_SEPARATOR, s, line)?;
+                        already_printed = true;
+                    }
+                }
+            }
+        }
+        if !already_printed {
+            write!(self.out, "  at {}:{}", file.display(), line)?;
+        }
+
+        self.out.write_all(b"\n")
+    }
 }
diff --git a/src/libstd/sys_common/gnu/libbacktrace.rs b/src/libstd/sys_common/gnu/libbacktrace.rs
deleted file mode 100644
index 6cd050242dd..00000000000
--- a/src/libstd/sys_common/gnu/libbacktrace.rs
+++ /dev/null
@@ -1,175 +0,0 @@
-use backtrace_sys::backtrace_state;
-
-use crate::ffi::CStr;
-use crate::io;
-use crate::mem;
-use crate::ptr;
-use crate::sys::backtrace::BacktraceContext;
-use crate::sys_common::backtrace::Frame;
-
-pub fn foreach_symbol_fileline<F>(frame: Frame,
-                                  mut f: F,
-                                  _: &BacktraceContext) -> io::Result<bool>
-where F: FnMut(&[u8], u32) -> io::Result<()>
-{
-    // pcinfo may return an arbitrary number of file:line pairs,
-    // in the order of stack trace (i.e., inlined calls first).
-    // in order to avoid allocation, we stack-allocate a fixed size of entries.
-    const FILELINE_SIZE: usize = 32;
-    let mut fileline_buf = [(ptr::null(), !0); FILELINE_SIZE];
-    let ret;
-    let fileline_count = {
-        let state = unsafe { init_state() };
-        if state.is_null() {
-            return Err(io::Error::new(
-                io::ErrorKind::Other,
-                "failed to allocate libbacktrace state")
-            )
-        }
-        let mut fileline_win: &mut [FileLine] = &mut fileline_buf;
-        let fileline_addr = &mut fileline_win as *mut &mut [FileLine];
-        ret = unsafe {
-            backtrace_sys::backtrace_pcinfo(
-                state,
-                frame.exact_position as libc::uintptr_t,
-                pcinfo_cb,
-                error_cb,
-                fileline_addr as *mut libc::c_void,
-            )
-        };
-        FILELINE_SIZE - fileline_win.len()
-    };
-    if ret == 0 {
-        for &(file, line) in &fileline_buf[..fileline_count] {
-            if file.is_null() { continue; } // just to be sure
-            let file = unsafe { CStr::from_ptr(file).to_bytes() };
-            f(file, line)?;
-        }
-        Ok(fileline_count == FILELINE_SIZE)
-    } else {
-        Ok(false)
-    }
-}
-
-/// Converts a pointer to symbol to its string value.
-pub fn resolve_symname<F>(frame: Frame,
-                          callback: F,
-                          _: &BacktraceContext) -> io::Result<()>
-    where F: FnOnce(Option<&str>) -> io::Result<()>
-{
-    let symname = {
-        let state = unsafe { init_state() };
-        if state.is_null() {
-            return Err(io::Error::new(
-                io::ErrorKind::Other,
-                "failed to allocate libbacktrace state")
-            )
-        }
-        let mut data: *const libc::c_char = ptr::null();
-        let data_addr = &mut data as *mut *const libc::c_char;
-        let ret = unsafe {
-            backtrace_sys::backtrace_syminfo(
-                state,
-                frame.symbol_addr as libc::uintptr_t,
-                syminfo_cb,
-                error_cb,
-                data_addr as *mut libc::c_void,
-            )
-        };
-        if ret == 0 || data.is_null() {
-            None
-        } else {
-            unsafe {
-                CStr::from_ptr(data).to_str().ok()
-            }
-        }
-    };
-    callback(symname)
-}
-
-////////////////////////////////////////////////////////////////////////
-// helper callbacks
-////////////////////////////////////////////////////////////////////////
-
-type FileLine = (*const libc::c_char, u32);
-
-extern fn error_cb(_data: *mut libc::c_void, _msg: *const libc::c_char,
-                   _errnum: libc::c_int) {
-    // do nothing for now
-}
-extern fn syminfo_cb(data: *mut libc::c_void,
-                     _pc: libc::uintptr_t,
-                     symname: *const libc::c_char,
-                     _symval: libc::uintptr_t,
-                     _symsize: libc::uintptr_t) {
-    let slot = data as *mut *const libc::c_char;
-    unsafe { *slot = symname; }
-}
-extern fn pcinfo_cb(data: *mut libc::c_void,
-                    _pc: libc::uintptr_t,
-                    filename: *const libc::c_char,
-                    lineno: libc::c_int,
-                    _function: *const libc::c_char) -> libc::c_int {
-    if !filename.is_null() {
-        let slot = data as *mut &mut [FileLine];
-        let buffer = unsafe {ptr::read(slot)};
-
-        // if the buffer is not full, add file:line to the buffer
-        // and adjust the buffer for next possible calls to pcinfo_cb.
-        if !buffer.is_empty() {
-            buffer[0] = (filename, lineno as u32);
-            unsafe { ptr::write(slot, &mut buffer[1..]); }
-        }
-    }
-
-    0
-}
-
-// The libbacktrace API supports creating a state, but it does not
-// support destroying a state. I personally take this to mean that a
-// state is meant to be created and then live forever.
-//
-// I would love to register an at_exit() handler which cleans up this
-// state, but libbacktrace provides no way to do so.
-//
-// With these constraints, this function has a statically cached state
-// that is calculated the first time this is requested. Remember that
-// backtracing all happens serially (one global lock).
-//
-// Things don't work so well on not-Linux since libbacktrace can't track
-// down that executable this is. We at one point used env::current_exe but
-// it turns out that there are some serious security issues with that
-// approach.
-//
-// Specifically, on certain platforms like BSDs, a malicious actor can cause
-// an arbitrary file to be placed at the path returned by current_exe.
-// libbacktrace does not behave defensively in the presence of ill-formed
-// DWARF information, and has been demonstrated to segfault in at least one
-// case. There is no evidence at the moment to suggest that a more carefully
-// constructed file can't cause arbitrary code execution. As a result of all
-// of this, we don't hint libbacktrace with the path to the current process.
-unsafe fn init_state() -> *mut backtrace_state {
-    static mut STATE: *mut backtrace_state = ptr::null_mut();
-    if !STATE.is_null() { return STATE  }
-
-    let filename = match crate::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_sys::backtrace_create_state(
-        filename,
-        0,
-        error_cb,
-        ptr::null_mut(),
-    );
-    STATE
-}
diff --git a/src/libstd/sys_common/gnu/mod.rs b/src/libstd/sys_common/gnu/mod.rs
deleted file mode 100644
index d6959697f2a..00000000000
--- a/src/libstd/sys_common/gnu/mod.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-#![allow(missing_docs)]
-#![allow(non_camel_case_types)]
-#![allow(non_snake_case)]
-
-pub mod libbacktrace;
diff --git a/src/libstd/sys_common/io.rs b/src/libstd/sys_common/io.rs
index 44b0963302d..8789abe55c3 100644
--- a/src/libstd/sys_common/io.rs
+++ b/src/libstd/sys_common/io.rs
@@ -16,7 +16,7 @@ pub mod test {
             p.join(path)
         }
 
-        pub fn path<'a>(&'a self) -> &'a Path {
+        pub fn path(&self) -> &Path {
             let TempDir(ref p) = *self;
             p
         }
diff --git a/src/libstd/sys_common/mod.rs b/src/libstd/sys_common/mod.rs
index 78e15994264..9190a3b0d5f 100644
--- a/src/libstd/sys_common/mod.rs
+++ b/src/libstd/sys_common/mod.rs
@@ -65,10 +65,9 @@ pub mod bytestring;
 pub mod process;
 pub mod fs;
 
-cfg_if! {
+cfg_if::cfg_if! {
     if #[cfg(any(target_os = "cloudabi",
                  target_os = "l4re",
-                 target_os = "redox",
                  all(target_arch = "wasm32", not(target_os = "emscripten")),
                  all(target_vendor = "fortanix", target_env = "sgx")))] {
         pub use crate::sys::net;
@@ -77,12 +76,6 @@ cfg_if! {
     }
 }
 
-#[cfg(feature = "backtrace")]
-#[cfg(any(all(unix, not(target_os = "emscripten")),
-          all(windows, target_env = "gnu"),
-          target_os = "redox"))]
-pub mod gnu;
-
 // common error constructors
 
 /// A trait for viewing representations from std types
diff --git a/src/libstd/sys_common/os_str_bytes.rs b/src/libstd/sys_common/os_str_bytes.rs
index a4961974d89..d734f412bf8 100644
--- a/src/libstd/sys_common/os_str_bytes.rs
+++ b/src/libstd/sys_common/os_str_bytes.rs
@@ -18,6 +18,12 @@ pub(crate) struct Buf {
     pub inner: Vec<u8>
 }
 
+// FIXME:
+// `Buf::as_slice` current implementation relies
+// on `Slice` being layout-compatible with `[u8]`.
+// When attribute privacy is implemented, `Slice` should be annotated as `#[repr(transparent)]`.
+// Anyway, `Slice` representation and layout are considered implementation detail, are
+// not documented and must not be relied upon.
 pub(crate) struct Slice {
     pub inner: [u8]
 }