From d96efb8346c3c250538f5bc9a0d3d84ce9855f91 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sat, 23 Mar 2024 19:19:38 +0100 Subject: [PATCH 01/26] Revert "Use rustc from stage0 instead of stage0-sysroot" (rust-lang/backtrace#603) This reverts commit c31ea5ba7ac52f5c15c65cfec7d7b5d0bcf00eed (rust-lang/backtrace#602). Don't do that, we need to use stage0-sysroot, bootstrap is just buggy. --- .github/actions/build-with-patched-std/action.yml | 2 +- .github/workflows/check-binary-size.yml | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/actions/build-with-patched-std/action.yml b/.github/actions/build-with-patched-std/action.yml index bdd127a38..5466a2289 100644 --- a/.github/actions/build-with-patched-std/action.yml +++ b/.github/actions/build-with-patched-std/action.yml @@ -41,7 +41,7 @@ runs: python3 x.py build library --stage 0 TEMP_BUILD_OUTPUT=$(mktemp test-binary-XXXXXXXX) - "$RUSTC_BUILD_DIR/stage0/bin/rustc" $RUSTC_FLAGS "${{ inputs.main-rs }}" -o "$TEMP_BUILD_OUTPUT" + "$RUSTC_BUILD_DIR/stage0-sysroot/bin/rustc" $RUSTC_FLAGS "${{ inputs.main-rs }}" -o "$TEMP_BUILD_OUTPUT" BINARY_SIZE=$(stat -c '%s' "$TEMP_BUILD_OUTPUT") rm "$TEMP_BUILD_OUTPUT" diff --git a/.github/workflows/check-binary-size.yml b/.github/workflows/check-binary-size.yml index d045fb7b3..5f4ec6168 100644 --- a/.github/workflows/check-binary-size.yml +++ b/.github/workflows/check-binary-size.yml @@ -6,8 +6,9 @@ name: Check binary size on: pull_request_target: - branches: - - master + # HACK(jubilee): something broke the distributed LLVM libso and I don't know what. + branches: [] +# - master # Both the "measure" and "report" jobs need to know this. env: From b76177c827a88e4452e0b78bbd5c57b06e6e96c9 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sat, 23 Mar 2024 06:15:28 +0000 Subject: [PATCH 02/26] Test nightly and stable Windows --- .github/workflows/main.yml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ba83f75c4..f8671dab1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -26,13 +26,18 @@ jobs: rust: stable - os: macos-latest rust: nightly - # HACK(jubilee): 1.77 broke backtraces on Windows lol - os: windows-latest - rust: 1.76.0-x86_64-msvc + rust: stable-x86_64-msvc - os: windows-latest - rust: 1.76.0-i686-msvc + rust: stable-i686-msvc - os: windows-latest - rust: 1.76.0-x86_64-gnu + rust: stable-x86_64-gnu + - os: windows-latest + rust: nightly-x86_64-msvc + - os: windows-latest + rust: nightly-i686-msvc + - os: windows-latest + rust: nightly-x86_64-gnu steps: - uses: actions/checkout@v3 with: From 8ff9b686672c803a61d824b1828e5efa1468bebe Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 27 Mar 2024 06:21:54 +0000 Subject: [PATCH 03/26] Remove dead code --- src/symbolize/gimli.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/symbolize/gimli.rs b/src/symbolize/gimli.rs index fa8e59723..51f1c8034 100644 --- a/src/symbolize/gimli.rs +++ b/src/symbolize/gimli.rs @@ -472,10 +472,7 @@ pub unsafe fn resolve(what: ResolveWhat<'_>, cb: &mut dyn FnMut(&super::Symbol)) } if !any_frames { if let Some(name) = cx.object.search_symtab(addr as u64) { - call(Symbol::Symtab { - addr: addr as *mut c_void, - name, - }); + call(Symbol::Symtab { name }); } } }); @@ -491,7 +488,7 @@ pub enum Symbol<'a> { }, /// Couldn't find debug information, but we found it in the symbol table of /// the elf executable. - Symtab { addr: *mut c_void, name: &'a [u8] }, + Symtab { name: &'a [u8] }, } impl Symbol<'_> { From 6bc4fcabc01a3937ec12cf8e4b9e0101cfc08857 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Thu, 28 Mar 2024 13:02:58 +0000 Subject: [PATCH 04/26] Remove all traces of rustc-serialize --- .github/workflows/main.yml | 1 - Cargo.lock | 7 ------ Cargo.toml | 14 +++++------ src/capture.rs | 49 -------------------------------------- src/lib.rs | 2 -- tests/smoke.rs | 12 ---------- 6 files changed, 7 insertions(+), 78 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f8671dab1..b1dc816b7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -57,7 +57,6 @@ jobs: - run: cargo build - run: cargo test - - run: cargo test --features "serialize-rustc" - run: cargo test --features "serialize-serde" - run: cargo test --features "verify-winapi" - run: cargo test --features "cpp_demangle" diff --git a/Cargo.lock b/Cargo.lock index ba8c53f4d..af2bbad89 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -44,7 +44,6 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "rustc-serialize", "serde", "winapi", ] @@ -152,12 +151,6 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" -[[package]] -name = "rustc-serialize" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe834bc780604f4674073badbad26d7219cadfb4a2275802db12cbae17498401" - [[package]] name = "serde" version = "1.0.188" diff --git a/Cargo.toml b/Cargo.toml index e1ee1c371..9bd7b63c7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,10 +20,10 @@ rust-version = "1.65.0" [workspace] members = ['crates/cpp_smoke_test', 'crates/as-if-std'] exclude = [ - 'crates/without_debuginfo', - 'crates/macos_frames_test', - 'crates/line-tables-only', - 'crates/debuglink', + 'crates/without_debuginfo', + 'crates/macos_frames_test', + 'crates/line-tables-only', + 'crates/debuglink', ] [dependencies] @@ -33,10 +33,11 @@ rustc-demangle = "0.1.4" # Optionally enable the ability to serialize a `Backtrace`, controlled through # the `serialize-*` features below. serde = { version = "1.0", optional = true, features = ['derive'] } -rustc-serialize = { version = "0.3", optional = true } # Optionally demangle C++ frames' symbols in backtraces. -cpp_demangle = { default-features = false, version = "0.4.0", optional = true, features = ["alloc"] } +cpp_demangle = { default-features = false, version = "0.4.0", optional = true, features = [ + "alloc", +] } [target.'cfg(not(all(windows, target_env = "msvc", not(target_vendor = "uwp"))))'.dependencies] miniz_oxide = { version = "0.7.0", default-features = false } @@ -71,7 +72,6 @@ std = [] # Methods of serialization # # Various features used for enabling rustc-serialize or syntex codegen. -serialize-rustc = ["rustc-serialize"] serialize-serde = ["serde"] #======================================= diff --git a/src/capture.rs b/src/capture.rs index 73d94dc4b..d1691b897 100644 --- a/src/capture.rs +++ b/src/capture.rs @@ -21,7 +21,6 @@ use serde::{Deserialize, Serialize}; /// This function requires the `std` feature of the `backtrace` crate to be /// enabled, and the `std` feature is enabled by default. #[derive(Clone)] -#[cfg_attr(feature = "serialize-rustc", derive(RustcDecodable, RustcEncodable))] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct Backtrace { // Frames here are listed from top-to-bottom of the stack @@ -116,7 +115,6 @@ impl Frame { /// This function requires the `std` feature of the `backtrace` crate to be /// enabled, and the `std` feature is enabled by default. #[derive(Clone)] -#[cfg_attr(feature = "serialize-rustc", derive(RustcDecodable, RustcEncodable))] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct BacktraceSymbol { name: Option>, @@ -440,53 +438,6 @@ impl fmt::Debug for BacktraceSymbol { } } -#[cfg(feature = "serialize-rustc")] -mod rustc_serialize_impls { - use super::*; - use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; - - #[derive(RustcEncodable, RustcDecodable)] - struct SerializedFrame { - ip: usize, - symbol_address: usize, - module_base_address: Option, - symbols: Option>, - } - - impl Decodable for BacktraceFrame { - fn decode(d: &mut D) -> Result - where - D: Decoder, - { - let frame: SerializedFrame = SerializedFrame::decode(d)?; - Ok(BacktraceFrame { - frame: Frame::Deserialized { - ip: frame.ip, - symbol_address: frame.symbol_address, - module_base_address: frame.module_base_address, - }, - symbols: frame.symbols, - }) - } - } - - impl Encodable for BacktraceFrame { - fn encode(&self, e: &mut E) -> Result<(), E::Error> - where - E: Encoder, - { - let BacktraceFrame { frame, symbols } = self; - SerializedFrame { - ip: frame.ip() as usize, - symbol_address: frame.symbol_address() as usize, - module_base_address: frame.module_base_address().map(|addr| addr as usize), - symbols: symbols.clone(), - } - .encode(e) - } - } -} - #[cfg(feature = "serde")] mod serde_impls { use super::*; diff --git a/src/lib.rs b/src/lib.rs index 5b97281a7..7b4bbc2e4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -97,8 +97,6 @@ // irrelevant as this crate is developed out-of-tree. #![cfg_attr(backtrace_in_libstd, allow(warnings))] #![cfg_attr(not(feature = "std"), allow(dead_code))] -// We know this is deprecated, it's only here for back-compat reasons. -#![cfg_attr(feature = "rustc-serialize", allow(deprecated))] #[cfg(feature = "std")] #[macro_use] diff --git a/tests/smoke.rs b/tests/smoke.rs index b47f02323..9c87f530e 100644 --- a/tests/smoke.rs +++ b/tests/smoke.rs @@ -230,18 +230,6 @@ fn many_threads() { } } -#[test] -#[cfg(feature = "rustc-serialize")] -fn is_rustc_serialize() { - extern crate rustc_serialize; - - fn is_encode() {} - fn is_decode() {} - - is_encode::(); - is_decode::(); -} - #[test] #[cfg(feature = "serde")] fn is_serde() { From d80990b05d9d97932b0ee9c80fa9a4466fa6495f Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Thu, 28 Mar 2024 18:42:04 +0000 Subject: [PATCH 05/26] Remove addr in gimli::Symbol::Symtab (rust-lang/backtrace-rs#605) --- src/symbolize/gimli.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/symbolize/gimli.rs b/src/symbolize/gimli.rs index fa8e59723..51f1c8034 100644 --- a/src/symbolize/gimli.rs +++ b/src/symbolize/gimli.rs @@ -472,10 +472,7 @@ pub unsafe fn resolve(what: ResolveWhat<'_>, cb: &mut dyn FnMut(&super::Symbol)) } if !any_frames { if let Some(name) = cx.object.search_symtab(addr as u64) { - call(Symbol::Symtab { - addr: addr as *mut c_void, - name, - }); + call(Symbol::Symtab { name }); } } }); @@ -491,7 +488,7 @@ pub enum Symbol<'a> { }, /// Couldn't find debug information, but we found it in the symbol table of /// the elf executable. - Symtab { addr: *mut c_void, name: &'a [u8] }, + Symtab { name: &'a [u8] }, } impl Symbol<'_> { From adc9f5ca6205a7bde95b5f1a3f029e590ce6c694 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Thu, 28 Mar 2024 18:48:03 +0000 Subject: [PATCH 06/26] Correct base address and update dbghelp64 comment (rust-lang/backtrace-rs#604) I've been staring at the code a lot lately but somehow missed that we're returning the wrong thing for the module base. It *probably* works out ok because a) most things only care that the pointer points to something within the right module and b) backtrace doesn't use it. I added a comment because apparently I need the obvious pointed out to me. Also while I'm at it I updated a 64-bit comment to remove the stuff commenting on 32-bit code (which is now in another file). --- src/backtrace/dbghelp64.rs | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/backtrace/dbghelp64.rs b/src/backtrace/dbghelp64.rs index d3ae06dff..9e7c9a0dd 100644 --- a/src/backtrace/dbghelp64.rs +++ b/src/backtrace/dbghelp64.rs @@ -1,19 +1,10 @@ -//! Backtrace strategy for MSVC platforms. +//! Backtrace strategy for MSVC `x86_64` and `aarch64` platforms. //! -//! This module contains the ability to capture a backtrace on MSVC using one -//! of three possible methods. For `x86_64` and `aarch64`, we use `RtlVirtualUnwind` -//! to walk the stack one frame at a time. This function is much faster than using +//! This module contains the ability to capture a backtrace on MSVC using +//! `RtlVirtualUnwind` to walk the stack one frame at a time. This function is much faster than using //! `dbghelp!StackWalk*` because it does not load debug info to report inlined frames. //! We still report inlined frames during symbolization by consulting the appropriate //! `dbghelp` functions. -//! -//! For all other platforms, primarily `i686`, the `StackWalkEx` function is used if -//! possible, but not all systems have that. Failing that the `StackWalk64` function -//! is used instead. Note that `StackWalkEx` is favored because it handles debuginfo -//! internally and returns inline frame information. -//! -//! Note that all dbghelp support is loaded dynamically, see `src/dbghelp.rs` -//! for more information about that. #![allow(bad_style)] @@ -100,6 +91,8 @@ pub unsafe fn trace(cb: &mut dyn FnMut(&super::Frame) -> bool) { // Call `RtlVirtualUnwind` to find the previous stack frame, walking until we hit ip = 0. while context.ip() != 0 { + // The base address of the module containing the function will be stored here + // when RtlLookupFunctionEntry returns successfully. let mut base = 0; let fn_entry = RtlLookupFunctionEntry(context.ip(), &mut base, ptr::null_mut()); @@ -109,7 +102,7 @@ pub unsafe fn trace(cb: &mut dyn FnMut(&super::Frame) -> bool) { let frame = super::Frame { inner: Frame { - base_address: fn_entry.cast::(), + base_address: base as *mut c_void, ip: context.ip() as *mut c_void, sp: context.sp() as *mut c_void, #[cfg(not(target_env = "gnu"))] From 3b96ddb6514b28e329da5de892166b015cb9f1ee Mon Sep 17 00:00:00 2001 From: Daniel Paoliello Date: Tue, 9 Apr 2024 15:53:54 -0700 Subject: [PATCH 07/26] Windows AArch64: Break out of tracing when no longer making progress --- src/backtrace/dbghelp64.rs | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/src/backtrace/dbghelp64.rs b/src/backtrace/dbghelp64.rs index 9e7c9a0dd..78929e9f5 100644 --- a/src/backtrace/dbghelp64.rs +++ b/src/backtrace/dbghelp64.rs @@ -86,46 +86,66 @@ impl MyContext { pub unsafe fn trace(cb: &mut dyn FnMut(&super::Frame) -> bool) { use core::ptr; + // Capture the initial context to start walking from. let mut context = core::mem::zeroed::(); RtlCaptureContext(&mut context.0); - // Call `RtlVirtualUnwind` to find the previous stack frame, walking until we hit ip = 0. - while context.ip() != 0 { + loop { + let ip = context.ip(); + // The base address of the module containing the function will be stored here // when RtlLookupFunctionEntry returns successfully. let mut base = 0; - - let fn_entry = RtlLookupFunctionEntry(context.ip(), &mut base, ptr::null_mut()); + let fn_entry = RtlLookupFunctionEntry(ip, &mut base, ptr::null_mut()); if fn_entry.is_null() { + // No function entry could be found - this may indicate a corrupt + // stack or that a binary was unloaded (amongst other issues). Stop + // walking and don't call the callback as we can't be confident in + // this frame or the rest of the stack. break; } let frame = super::Frame { inner: Frame { base_address: base as *mut c_void, - ip: context.ip() as *mut c_void, + ip: ip as *mut c_void, sp: context.sp() as *mut c_void, #[cfg(not(target_env = "gnu"))] inline_context: None, }, }; + // We've loaded all the info about the current frame, so now call the + // callback. if !cb(&frame) { + // Callback told us to stop, so we're done. break; } + // Unwind to the next frame. + let previous_ip = ip; + let previous_sp = context.sp(); let mut handler_data = 0usize; let mut establisher_frame = 0; - RtlVirtualUnwind( 0, base, - context.ip(), + ip, fn_entry, &mut context.0, ptr::addr_of_mut!(handler_data).cast::(), &mut establisher_frame, ptr::null_mut(), ); + + // RtlVirtualUnwind indicates the end of the stack in two different ways: + // * On x64, it sets the instruction pointer to 0. + // * On ARM64, it leaves the context unchanged (easiest way to check is + // to see if the instruction and stack pointers are the same). + // If we detect either of these, then unwinding is completed. + let ip = context.ip(); + if ip == 0 || (ip == previous_ip && context.sp() == previous_sp) { + break; + } } } From 86646307c5ede8df28ad1ef5de2b206fd73da910 Mon Sep 17 00:00:00 2001 From: Alex Touchet Date: Mon, 6 May 2024 10:55:18 -0700 Subject: [PATCH 08/26] Remove obsolete rustc-serialize references (rust-lang/backtrace-rs#614) --- Cargo.toml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9bd7b63c7..294ee1b41 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ cfg-if = "1.0" rustc-demangle = "0.1.4" # Optionally enable the ability to serialize a `Backtrace`, controlled through -# the `serialize-*` features below. +# the `serialize-serde` feature below. serde = { version = "1.0", optional = true, features = ['derive'] } # Optionally demangle C++ frames' symbols in backtraces. @@ -68,10 +68,6 @@ default = ["std"] # Include std support. This enables types like `Backtrace`. std = [] -#======================================= -# Methods of serialization -# -# Various features used for enabling rustc-serialize or syntex codegen. serialize-serde = ["serde"] #======================================= From 4c7c1def72495bd0d8189a0f219317029b381ec0 Mon Sep 17 00:00:00 2001 From: Alphyr <47725341+a1phyr@users.noreply.github.com> Date: Mon, 6 May 2024 20:04:52 +0200 Subject: [PATCH 09/26] Update `object` and `addr2line` dependencies (rust-lang/backtrace-rs#612) --- Cargo.lock | 12 ++++++------ Cargo.toml | 4 ++-- crates/as-if-std/Cargo.toml | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index af2bbad89..52472f32e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ "gimli", ] @@ -83,9 +83,9 @@ version = "0.1.0" [[package]] name = "gimli" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" [[package]] name = "libc" @@ -120,9 +120,9 @@ dependencies = [ [[package]] name = "object" -version = "0.32.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe" +checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index 294ee1b41..c8203b173 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,11 +41,11 @@ cpp_demangle = { default-features = false, version = "0.4.0", optional = true, f [target.'cfg(not(all(windows, target_env = "msvc", not(target_vendor = "uwp"))))'.dependencies] miniz_oxide = { version = "0.7.0", default-features = false } -addr2line = { version = "0.21.0", default-features = false } +addr2line = { version = "0.22.0", default-features = false } libc = { version = "0.2.146", default-features = false } [target.'cfg(not(all(windows, target_env = "msvc", not(target_vendor = "uwp"))))'.dependencies.object] -version = "0.32.0" +version = "0.35.0" default-features = false features = ['read_core', 'elf', 'macho', 'pe', 'xcoff', 'unaligned', 'archive'] diff --git a/crates/as-if-std/Cargo.toml b/crates/as-if-std/Cargo.toml index 1618058de..031b66569 100644 --- a/crates/as-if-std/Cargo.toml +++ b/crates/as-if-std/Cargo.toml @@ -18,10 +18,10 @@ libc = { version = "0.2.146", default-features = false } [target.'cfg(not(all(windows, target_env = "msvc", not(target_vendor = "uwp"))))'.dependencies] miniz_oxide = { version = "0.7.0", optional = true, default-features = false } -addr2line = { version = "0.21.0", optional = true, default-features = false } +addr2line = { version = "0.22.0", optional = true, default-features = false } [target.'cfg(not(all(windows, target_env = "msvc", not(target_vendor = "uwp"))))'.dependencies.object] -version = "0.32.0" +version = "0.35.0" default-features = false optional = true features = ['read_core', 'elf', 'macho', 'pe', 'xcoff', 'unaligned', 'archive'] From 9ca9f5dacc6d8afe964cc2417992769b7aa0ba24 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Mon, 6 May 2024 12:12:27 -0700 Subject: [PATCH 10/26] Fix accuracy tests for rust 1.79 --- .github/workflows/main.yml | 5 +++++ tests/accuracy/main.rs | 2 ++ 2 files changed, 7 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b1dc816b7..0a00ab578 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -55,6 +55,11 @@ jobs: shell: bash if: contains(matrix.rust, 'i686') + - name: Enable collapse_debuginfo based on version + run: echo RUSTFLAGS="--cfg dbginfo=\"collapsible\" $RUSTFLAGS" >> $GITHUB_ENV + shell: bash + if: contains(matrix.rust, 'nightly') || contains(matrix.rust, 'beta') + - run: cargo build - run: cargo test - run: cargo test --features "serialize-serde" diff --git a/tests/accuracy/main.rs b/tests/accuracy/main.rs index 568acab84..ada842d28 100644 --- a/tests/accuracy/main.rs +++ b/tests/accuracy/main.rs @@ -1,3 +1,4 @@ +#![cfg(dbginfo = "collapsible")] mod auxiliary; macro_rules! pos { @@ -6,6 +7,7 @@ macro_rules! pos { }; } +#[collapse_debuginfo(yes)] macro_rules! check { ($($pos:expr),*) => ({ verify(&[$($pos,)* pos!()]); From 3a8d3a651ad08e3ccd5742dcfcd5f5ca216d9edd Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Mon, 6 May 2024 12:31:01 -0700 Subject: [PATCH 11/26] Add dl_iterate_phdr to deprecated features It may not be actually deprecated yet but it soon will be --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index c8203b173..2455af7ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -77,6 +77,7 @@ serialize-serde = ["serde"] # purposes. New code should use none of these features. coresymbolication = [] dbghelp = [] +dl_iterate_phdr = [] dladdr = [] gimli-symbolize = [] kernel32 = [] From a042ce7306ebe3ad85912679e03d143a6a85cb44 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Mon, 6 May 2024 12:34:31 -0700 Subject: [PATCH 12/26] Allow all other unexpected cfgs --- Cargo.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 2455af7ec..5c34bdef0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -132,3 +132,7 @@ harness = false name = "current-exe-mismatch" required-features = ["std"] harness = false + +[lints.rust] +# This crate uses them pervasively +unexpected_cfgs = "allow" From fc5a3a60ab06a5c156337472975471bece2aff7e Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Mon, 6 May 2024 12:38:47 -0700 Subject: [PATCH 13/26] Be quiet! --- crates/as-if-std/Cargo.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/as-if-std/Cargo.toml b/crates/as-if-std/Cargo.toml index 031b66569..b451c024a 100644 --- a/crates/as-if-std/Cargo.toml +++ b/crates/as-if-std/Cargo.toml @@ -33,3 +33,7 @@ cc = "1.0.90" [features] default = ['backtrace'] backtrace = ['addr2line', 'miniz_oxide', 'object'] +std = [] + +[lints.rust] +unexpected_cfgs = "allow" From 74d8f947ce0d165a9ca700e1e7e970df00db35ee Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Mon, 6 May 2024 12:55:53 -0700 Subject: [PATCH 14/26] Consistently rustup update --no-self-update --- .github/workflows/main.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0a00ab578..30253a74d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -199,7 +199,7 @@ jobs: with: submodules: true - name: Install Rust - run: rustup update stable && rustup default stable + run: rustup update stable --no-self-update && rustup default stable - run: rustup target add ${{ matrix.target }} - run: cargo generate-lockfile - run: echo RUSTFLAGS=-Dwarnings >> $GITHUB_ENV @@ -214,7 +214,7 @@ jobs: with: submodules: true - name: Install Rust - run: rustup update stable && rustup default stable && rustup component add rustfmt + run: rustup update stable --no-self-update && rustup default stable && rustup component add rustfmt - run: cargo fmt --all -- --check build: @@ -233,7 +233,7 @@ jobs: with: submodules: true - name: Install Rust - run: rustup update nightly && rustup default nightly + run: rustup update nightly --no-self-update && rustup default nightly - run: rustup target add ${{ matrix.target }} - run: echo RUSTFLAGS=-Dwarnings >> $GITHUB_ENV shell: bash @@ -254,7 +254,7 @@ jobs: with: submodules: true - name: Install Rust - run: rustup update 1.65.0 && rustup default 1.65.0 + run: rustup update 1.65.0 --no-self-update && rustup default 1.65.0 - run: cargo build miri: From 0968bea4f1e0b5c545ed312993bfc2c491980d3c Mon Sep 17 00:00:00 2001 From: klensy Date: Sat, 4 May 2024 15:19:13 +0300 Subject: [PATCH 15/26] move Bomb into libunwind, remove dead_code --- src/backtrace/libunwind.rs | 13 ++++++++++++- src/lib.rs | 14 -------------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/backtrace/libunwind.rs b/src/backtrace/libunwind.rs index c3d88605c..d439be069 100644 --- a/src/backtrace/libunwind.rs +++ b/src/backtrace/libunwind.rs @@ -15,7 +15,6 @@ //! //! This is the default unwinding API for all non-Windows platforms currently. -use super::super::Bomb; use core::ffi::c_void; use core::ptr::addr_of_mut; @@ -100,6 +99,18 @@ impl Clone for Frame { } } +struct Bomb { + enabled: bool, +} + +impl Drop for Bomb { + fn drop(&mut self) { + if self.enabled { + panic!("cannot panic during the backtrace function"); + } + } +} + #[inline(always)] pub unsafe fn trace(mut cb: &mut dyn FnMut(&super::Frame) -> bool) { uw::_Unwind_Backtrace(trace_fn, addr_of_mut!(cb).cast()); diff --git a/src/lib.rs b/src/lib.rs index 7b4bbc2e4..ccb2f454d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -138,20 +138,6 @@ cfg_if::cfg_if! { } } -#[allow(dead_code)] -struct Bomb { - enabled: bool, -} - -#[allow(dead_code)] -impl Drop for Bomb { - fn drop(&mut self) { - if self.enabled { - panic!("cannot panic during the backtrace function"); - } - } -} - #[allow(dead_code)] #[cfg(feature = "std")] mod lock { From 58d4b135510384783fdc31c3a7621fcc9e42c136 Mon Sep 17 00:00:00 2001 From: klensy Date: Sat, 4 May 2024 15:32:19 +0300 Subject: [PATCH 16/26] replace some allow dead_code with feature == "serde" --- src/capture.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/capture.rs b/src/capture.rs index d1691b897..f7d4b4fea 100644 --- a/src/capture.rs +++ b/src/capture.rs @@ -1,5 +1,7 @@ +#[cfg(feature = "serde")] +use crate::resolve; use crate::PrintFmt; -use crate::{resolve, resolve_frame, trace, BacktraceFmt, Symbol, SymbolName}; +use crate::{resolve_frame, trace, BacktraceFmt, Symbol, SymbolName}; use std::ffi::c_void; use std::fmt; use std::path::{Path, PathBuf}; @@ -50,7 +52,7 @@ pub struct BacktraceFrame { #[derive(Clone)] enum Frame { Raw(crate::Frame), - #[allow(dead_code)] + #[cfg(feature = "serde")] Deserialized { ip: usize, symbol_address: usize, @@ -62,6 +64,7 @@ impl Frame { fn ip(&self) -> *mut c_void { match *self { Frame::Raw(ref f) => f.ip(), + #[cfg(feature = "serde")] Frame::Deserialized { ip, .. } => ip as *mut c_void, } } @@ -69,6 +72,7 @@ impl Frame { fn symbol_address(&self) -> *mut c_void { match *self { Frame::Raw(ref f) => f.symbol_address(), + #[cfg(feature = "serde")] Frame::Deserialized { symbol_address, .. } => symbol_address as *mut c_void, } } @@ -76,6 +80,7 @@ impl Frame { fn module_base_address(&self) -> Option<*mut c_void> { match *self { Frame::Raw(ref f) => f.module_base_address(), + #[cfg(feature = "serde")] Frame::Deserialized { module_base_address, .. @@ -97,6 +102,7 @@ impl Frame { }; match *self { Frame::Raw(ref f) => resolve_frame(f, sym), + #[cfg(feature = "serde")] Frame::Deserialized { ip, .. } => { resolve(ip as *mut c_void, sym); } From f996e668140042d93e4f69354a637ee9bdbdc4cc Mon Sep 17 00:00:00 2001 From: klensy Date: Sat, 4 May 2024 15:43:07 +0300 Subject: [PATCH 17/26] remove dead_code from mod lock --- src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index ccb2f454d..e9be4009a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -138,7 +138,6 @@ cfg_if::cfg_if! { } } -#[allow(dead_code)] #[cfg(feature = "std")] mod lock { use std::boxed::Box; From 4cbe6b69eaccf23297b51f9584dd8a7d5e12ea95 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Mon, 6 May 2024 23:29:14 +0200 Subject: [PATCH 18/26] Remove unused `libbacktrace` and `gimli-symbolize` features (rust-lang/backtrace-rs#615) --- .github/workflows/main.yml | 4 ++-- Cargo.toml | 2 -- crates/line-tables-only/Cargo.toml | 4 ---- crates/without_debuginfo/Cargo.toml | 4 ---- src/symbolize/mod.rs | 2 +- 5 files changed, 3 insertions(+), 13 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 30253a74d..6ed2863cf 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -73,8 +73,8 @@ jobs: env: CARGO_PROFILE_DEV_SPLIT_DEBUGINFO: packed CARGO_PROFILE_TEST_SPLIT_DEBUGINFO: packed - - run: cargo test --features gimli-symbolize --manifest-path crates/without_debuginfo/Cargo.toml - - run: cargo test --manifest-path crates/line-tables-only/Cargo.toml --features gimli-symbolize + - run: cargo test --manifest-path crates/without_debuginfo/Cargo.toml + - run: cargo test --manifest-path crates/line-tables-only/Cargo.toml # Test debuginfo compression still works - run: cargo test diff --git a/Cargo.toml b/Cargo.toml index 5c34bdef0..e6c6b02f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -79,9 +79,7 @@ coresymbolication = [] dbghelp = [] dl_iterate_phdr = [] dladdr = [] -gimli-symbolize = [] kernel32 = [] -libbacktrace = [] libunwind = [] unix-backtrace = [] verify-winapi = [ diff --git a/crates/line-tables-only/Cargo.toml b/crates/line-tables-only/Cargo.toml index 8d17db58c..4aa28f6a0 100644 --- a/crates/line-tables-only/Cargo.toml +++ b/crates/line-tables-only/Cargo.toml @@ -15,7 +15,3 @@ features = [ 'libunwind', 'std', ] - -[features] -libbacktrace = ['backtrace/libbacktrace'] -gimli-symbolize = ['backtrace/gimli-symbolize'] diff --git a/crates/without_debuginfo/Cargo.toml b/crates/without_debuginfo/Cargo.toml index 38e559971..b8c939414 100644 --- a/crates/without_debuginfo/Cargo.toml +++ b/crates/without_debuginfo/Cargo.toml @@ -14,7 +14,3 @@ debug = false [profile.test] debug = false - -[features] -libbacktrace = ['backtrace/libbacktrace'] -gimli-symbolize = ['backtrace/gimli-symbolize'] diff --git a/src/symbolize/mod.rs b/src/symbolize/mod.rs index b01fe86d6..3f5e2f1c5 100644 --- a/src/symbolize/mod.rs +++ b/src/symbolize/mod.rs @@ -453,7 +453,7 @@ cfg_if::cfg_if! { /// While this function is always available it doesn't actually do anything on /// most implementations. Libraries like dbghelp or libbacktrace do not provide /// facilities to deallocate state and manage the allocated memory. For now the -/// `gimli-symbolize` feature of this crate is the only feature where this +/// `std` feature of this crate is the only feature where this /// function has any effect. #[cfg(feature = "std")] pub fn clear_symbol_cache() { From 7d263344f6bdc729db89304ccbbda7352acee7af Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 7 May 2024 06:35:43 +0000 Subject: [PATCH 19/26] Reduce panics in dbghelp (rust-lang/backtrace-rs#608) According to the docs for `resolve`: > The closure may not be called if resolution could not be performed > This function strives to never panic. So we should ideally not panic and instead simply return without calling the closure. Therefore, I've changed the panicky FFI calls to instead simply return. I also replaced our custom UTF-16 to UTF-8 converter with a call to `WideCharToMultiByte`. This function already has the semantics we want and doesn't include panicking code. These changes should have a small but notable effect on binary size. --- Cargo.toml | 2 ++ src/dbghelp.rs | 27 ++++++++-------- src/symbolize/dbghelp.rs | 66 +++++++++++++++++++--------------------- src/windows.rs | 13 ++++++++ 4 files changed, 62 insertions(+), 46 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e6c6b02f9..bf8cf869d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -93,6 +93,8 @@ verify-winapi = [ 'winapi/tlhelp32', 'winapi/winbase', 'winapi/winnt', + 'winapi/winnls', + 'winapi/stringapiset', ] [[example]] diff --git a/src/dbghelp.rs b/src/dbghelp.rs index 711b53db6..2226faf21 100644 --- a/src/dbghelp.rs +++ b/src/dbghelp.rs @@ -376,16 +376,21 @@ pub fn init() -> Result { DBGHELP.ensure_open()?; static mut INITIALIZED: bool = false; - if INITIALIZED { - return Ok(ret); + if !INITIALIZED { + set_optional_options(); + INITIALIZED = true; } - - let orig = DBGHELP.SymGetOptions().unwrap()(); + Ok(ret) + } +} +fn set_optional_options() -> Option<()> { + unsafe { + let orig = DBGHELP.SymGetOptions()?(); // Ensure that the `SYMOPT_DEFERRED_LOADS` flag is set, because // according to MSVC's own docs about this: "This is the fastest, most // efficient way to use the symbol handler.", so let's do that! - DBGHELP.SymSetOptions().unwrap()(orig | SYMOPT_DEFERRED_LOADS); + DBGHELP.SymSetOptions()?(orig | SYMOPT_DEFERRED_LOADS); // Actually initialize symbols with MSVC. Note that this can fail, but we // ignore it. There's not a ton of prior art for this per se, but LLVM @@ -399,7 +404,7 @@ pub fn init() -> Result { // the time, but now that it's using this crate it means that someone will // get to initialization first and the other will pick up that // initialization. - DBGHELP.SymInitializeW().unwrap()(GetCurrentProcess(), ptr::null_mut(), TRUE); + DBGHELP.SymInitializeW()?(GetCurrentProcess(), ptr::null_mut(), TRUE); // The default search path for dbghelp will only look in the current working // directory and (possibly) `_NT_SYMBOL_PATH` and `_NT_ALT_SYMBOL_PATH`. @@ -413,7 +418,7 @@ pub fn init() -> Result { search_path_buf.resize(1024, 0); // Prefill the buffer with the current search path. - if DBGHELP.SymGetSearchPathW().unwrap()( + if DBGHELP.SymGetSearchPathW()?( GetCurrentProcess(), search_path_buf.as_mut_ptr(), search_path_buf.len() as _, @@ -433,7 +438,7 @@ pub fn init() -> Result { let mut search_path = SearchPath::new(search_path_buf); // Update the search path to include the directory of the executable and each DLL. - DBGHELP.EnumerateLoadedModulesW64().unwrap()( + DBGHELP.EnumerateLoadedModulesW64()?( GetCurrentProcess(), Some(enum_loaded_modules_callback), ((&mut search_path) as *mut SearchPath) as *mut c_void, @@ -442,11 +447,9 @@ pub fn init() -> Result { let new_search_path = search_path.finalize(); // Set the new search path. - DBGHELP.SymSetSearchPathW().unwrap()(GetCurrentProcess(), new_search_path.as_ptr()); - - INITIALIZED = true; - Ok(ret) + DBGHELP.SymSetSearchPathW()?(GetCurrentProcess(), new_search_path.as_ptr()); } + Some(()) } struct SearchPath { diff --git a/src/symbolize/dbghelp.rs b/src/symbolize/dbghelp.rs index 50d5384f0..dc4646459 100644 --- a/src/symbolize/dbghelp.rs +++ b/src/symbolize/dbghelp.rs @@ -19,7 +19,6 @@ use super::super::{dbghelp, windows::*}; use super::{BytesOrWideString, ResolveWhat, SymbolName}; -use core::char; use core::ffi::c_void; use core::marker; use core::mem; @@ -91,7 +90,7 @@ pub unsafe fn resolve(what: ResolveWhat<'_>, cb: &mut dyn FnMut(&super::Symbol)) ResolveWhat::Frame(frame) => { resolve_with_inline(&dbghelp, frame.ip(), frame.inner.inline_context(), cb) } - } + }; } #[cfg(target_vendor = "win7")] @@ -116,7 +115,7 @@ pub unsafe fn resolve(what: ResolveWhat<'_>, cb: &mut dyn FnMut(&super::Symbol)) ResolveWhat::Frame(frame) => { resolve_inner(&dbghelp, frame.ip(), frame.inner.inline_context(), cb) } - } + }; } /// Resolve the address using the legacy dbghelp API. @@ -147,22 +146,28 @@ unsafe fn resolve_with_inline( addr: *mut c_void, inline_context: Option, cb: &mut dyn FnMut(&super::Symbol), -) { +) -> Option<()> { let current_process = GetCurrentProcess(); + // Ensure we have the functions we need. Return if any aren't found. + let SymFromInlineContextW = (*dbghelp.dbghelp()).SymFromInlineContextW()?; + let SymGetLineFromInlineContextW = (*dbghelp.dbghelp()).SymGetLineFromInlineContextW()?; let addr = super::adjust_ip(addr) as DWORD64; let (inlined_frame_count, inline_context) = if let Some(ic) = inline_context { (0, ic) } else { - let mut inlined_frame_count = dbghelp.SymAddrIncludeInlineTrace()(current_process, addr); + let SymAddrIncludeInlineTrace = (*dbghelp.dbghelp()).SymAddrIncludeInlineTrace()?; + let SymQueryInlineTrace = (*dbghelp.dbghelp()).SymQueryInlineTrace()?; + + let mut inlined_frame_count = SymAddrIncludeInlineTrace(current_process, addr); let mut inline_context = 0; // If there is are inlined frames but we can't load them for some reason OR if there are no // inlined frames, then we disregard inlined_frame_count and inline_context. if (inlined_frame_count > 0 - && dbghelp.SymQueryInlineTrace()( + && SymQueryInlineTrace( current_process, addr, 0, @@ -184,22 +189,14 @@ unsafe fn resolve_with_inline( for inline_context in inline_context..last_inline_context { do_resolve( - |info| { - dbghelp.SymFromInlineContextW()(current_process, addr, inline_context, &mut 0, info) - }, + |info| SymFromInlineContextW(current_process, addr, inline_context, &mut 0, info), |line| { - dbghelp.SymGetLineFromInlineContextW()( - current_process, - addr, - inline_context, - 0, - &mut 0, - line, - ) + SymGetLineFromInlineContextW(current_process, addr, inline_context, 0, &mut 0, line) }, cb, ); } + Some(()) } unsafe fn do_resolve( @@ -225,26 +222,27 @@ unsafe fn do_resolve( // the real value. let name_len = ::core::cmp::min(info.NameLen as usize, info.MaxNameLen as usize - 1); let name_ptr = info.Name.as_ptr().cast::(); - let name = slice::from_raw_parts(name_ptr, name_len); // Reencode the utf-16 symbol to utf-8 so we can use `SymbolName::new` like // all other platforms - let mut name_len = 0; - let mut name_buffer = [0; 256]; - { - let mut remaining = &mut name_buffer[..]; - for c in char::decode_utf16(name.iter().cloned()) { - let c = c.unwrap_or(char::REPLACEMENT_CHARACTER); - let len = c.len_utf8(); - if len < remaining.len() { - c.encode_utf8(remaining); - let tmp = remaining; - remaining = &mut tmp[len..]; - name_len += len; - } else { - break; - } - } + let mut name_buffer = [0_u8; 256]; + let mut name_len = WideCharToMultiByte( + CP_UTF8, + 0, + name_ptr, + name_len as i32, + name_buffer.as_mut_ptr().cast::(), + name_buffer.len() as i32, + core::ptr::null_mut(), + core::ptr::null_mut(), + ) as usize; + if name_len == 0 { + // If the returned length is zero that means the buffer wasn't big enough. + // However, the buffer will be filled with as much as will fit. + name_len = name_buffer.len(); + } else if name_len > name_buffer.len() { + // This can't happen. + return; } let name = ptr::addr_of!(name_buffer[..name_len]); diff --git a/src/windows.rs b/src/windows.rs index a95762d35..305da0570 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -38,6 +38,8 @@ cfg_if::cfg_if! { pub use winapi::um::tlhelp32::*; pub use winapi::um::winbase::*; pub use winapi::um::winnt::*; + pub use winapi::um::winnls::*; + pub use winapi::um::stringapiset::*; // Work around winapi not having this function on aarch64. #[cfg(target_arch = "aarch64")] @@ -379,6 +381,7 @@ ffi! { pub const INVALID_HANDLE_VALUE: HANDLE = -1isize as HANDLE; pub const MAX_MODULE_NAME32: usize = 255; pub const MAX_PATH: usize = 260; + pub const CP_UTF8: u32 = 65001; pub type DWORD = u32; pub type PDWORD = *mut u32; @@ -456,6 +459,16 @@ ffi! { lpme: LPMODULEENTRY32W, ) -> BOOL; pub fn lstrlenW(lpstring: PCWSTR) -> i32; + pub fn WideCharToMultiByte( + codepage: u32, + dwflags: u32, + lpwidecharstr: PCWSTR, + cchwidechar: i32, + lpmultibytestr: *mut i8, + cbmultibyte: i32, + lpdefaultchar: *const i8, + lpuseddefaultchar: *mut BOOL + ) -> i32; } } From 89eb2157cd6b0049e7c20aba3ab5032a4b2a0db4 Mon Sep 17 00:00:00 2001 From: Quentin Perez Date: Mon, 27 May 2024 05:15:02 +0200 Subject: [PATCH 20/26] Add Apple visionOS support (rust-lang/backtrace-rs#613) --- crates/macos_frames_test/tests/main.rs | 2 +- src/symbolize/gimli.rs | 19 +++++-------------- tests/accuracy/main.rs | 2 +- 3 files changed, 7 insertions(+), 16 deletions(-) diff --git a/crates/macos_frames_test/tests/main.rs b/crates/macos_frames_test/tests/main.rs index 5d74bdcc3..1eace1a23 100644 --- a/crates/macos_frames_test/tests/main.rs +++ b/crates/macos_frames_test/tests/main.rs @@ -6,7 +6,7 @@ // so that it gets its own 'target' directory. We manually invoke this test // in .github/workflows/main.yml by passing `--manifest-path` to Cargo #[test] -#[cfg(target_os = "macos")] +#[cfg(target_vendor = "apple")] fn backtrace_no_dsym() { use std::{env, fs}; diff --git a/src/symbolize/gimli.rs b/src/symbolize/gimli.rs index 51f1c8034..7465f755c 100644 --- a/src/symbolize/gimli.rs +++ b/src/symbolize/gimli.rs @@ -30,15 +30,16 @@ cfg_if::cfg_if! { if #[cfg(windows)] { #[path = "gimli/mmap_windows.rs"] mod mmap; + } else if #[cfg(target_vendor = "apple")] { + #[path = "gimli/mmap_unix.rs"] + mod mmap; } else if #[cfg(any( target_os = "android", target_os = "freebsd", target_os = "fuchsia", target_os = "haiku", target_os = "hurd", - target_os = "ios", target_os = "linux", - target_os = "macos", target_os = "openbsd", target_os = "solaris", target_os = "illumos", @@ -195,12 +196,7 @@ cfg_if::cfg_if! { if #[cfg(windows)] { mod coff; use self::coff::{handle_split_dwarf, Object}; - } else if #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "tvos", - target_os = "watchos", - ))] { + } else if #[cfg(any(target_vendor = "apple"))] { mod macho; use self::macho::{handle_split_dwarf, Object}; } else if #[cfg(target_os = "aix")] { @@ -216,12 +212,7 @@ cfg_if::cfg_if! { if #[cfg(windows)] { mod libs_windows; use libs_windows::native_libraries; - } else if #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "tvos", - target_os = "watchos", - ))] { + } else if #[cfg(target_vendor = "apple")] { mod libs_macos; use libs_macos::native_libraries; } else if #[cfg(target_os = "illumos")] { diff --git a/tests/accuracy/main.rs b/tests/accuracy/main.rs index ada842d28..b50e4451f 100644 --- a/tests/accuracy/main.rs +++ b/tests/accuracy/main.rs @@ -31,7 +31,7 @@ fn doit() { dir.pop(); if cfg!(windows) { dir.push("dylib_dep.dll"); - } else if cfg!(target_os = "macos") { + } else if cfg!(target_vendor = "apple") { dir.push("libdylib_dep.dylib"); } else if cfg!(target_os = "aix") { dir.push("libdylib_dep.a"); From ee06680cc5f207aee7d39770ab4efb2e2d479e38 Mon Sep 17 00:00:00 2001 From: James Farrell <83229348+jfgoog@users.noreply.github.com> Date: Sun, 26 May 2024 22:19:30 -0500 Subject: [PATCH 21/26] Update cc crate to v1.0.97 (rust-lang/backtrace-rs#623) --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- crates/as-if-std/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 52472f32e..30f0452b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -50,9 +50,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.90" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" +checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" [[package]] name = "cfg-if" diff --git a/Cargo.toml b/Cargo.toml index bf8cf869d..7c1a92042 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,7 +55,7 @@ winapi = { version = "0.3.9", optional = true } [build-dependencies] # Only needed for Android, but cannot be target dependent # https://github.com/rust-lang/cargo/issues/4932 -cc = "1.0.90" +cc = "1.0.97" [dev-dependencies] dylib-dep = { path = "crates/dylib-dep" } diff --git a/crates/as-if-std/Cargo.toml b/crates/as-if-std/Cargo.toml index b451c024a..527d21056 100644 --- a/crates/as-if-std/Cargo.toml +++ b/crates/as-if-std/Cargo.toml @@ -28,7 +28,7 @@ features = ['read_core', 'elf', 'macho', 'pe', 'xcoff', 'unaligned', 'archive'] [build-dependencies] # Dependency of the `backtrace` crate -cc = "1.0.90" +cc = "1.0.97" [features] default = ['backtrace'] From 6156427fc85481c772944f502d05883bb18628d6 Mon Sep 17 00:00:00 2001 From: Aria Beingessner Date: Sun, 26 May 2024 23:20:41 -0400 Subject: [PATCH 22/26] chore: add docs for the global re-entrant lock (rust-lang/backtrace-rs#609) --- src/lib.rs | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index e9be4009a..20e9ecb80 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -145,32 +145,95 @@ mod lock { use std::ptr; use std::sync::{Mutex, MutexGuard, Once}; + /// A "Maybe" LockGuard pub struct LockGuard(Option>); + /// The global lock, lazily allocated on first use static mut LOCK: *mut Mutex<()> = ptr::null_mut(); static INIT: Once = Once::new(); + // Whether this thread is the one that holds the lock thread_local!(static LOCK_HELD: Cell = Cell::new(false)); impl Drop for LockGuard { fn drop(&mut self) { + // Don't do anything if we're a LockGuard(None) if self.0.is_some() { LOCK_HELD.with(|slot| { + // Immediately crash if we somehow aren't the thread holding this lock assert!(slot.get()); + // We are no longer the thread holding this lock slot.set(false); }); } + // lock implicitly released here, if we're a LockGuard(Some(..)) } } + /// Acquire a partially unsound(!!!) global re-entrant lock over + /// backtrace's internals. + /// + /// That is, this lock can be acquired as many times as you want + /// on a single thread without deadlocking, allowing one thread + /// to acquire exclusive access to the ability to make backtraces. + /// Calls to this locking function are freely sprinkled in every place + /// where that needs to be enforced. + /// + /// + /// # Why + /// + /// This was first introduced to guard uses of Windows' dbghelp API, + /// which isn't threadsafe. It's unclear if other things now rely on + /// this locking. + /// + /// + /// # How + /// + /// The basic idea is to have a single global mutex, and a thread_local + /// boolean saying "yep this is the thread that acquired the mutex". + /// + /// The first time a thread acquires the lock, it is handed a + /// `LockGuard(Some(..))` that will actually release the lock on Drop. + /// All subsequence attempts to lock on the same thread will see + /// that their thread acquired the lock, and get `LockGuard(None)` + /// which will do nothing when dropped. + /// + /// + /// # Safety + /// + /// As long as you only ever assign the returned LockGuard to a freshly + /// declared local variable, it will do its job correctly, as the "first" + /// LockGuard will strictly outlive all subsequent LockGuards and + /// properly release the lock when the thread is done with backtracing. + /// + /// However if you ever attempt to store a LockGuard beyond the scope + /// it was acquired in, it might actually be a `LockGuard(None)` that + /// doesn't actually hold the lock! In this case another thread might + /// acquire the lock and you'll get races this system was intended to + /// avoid! + /// + /// This is why this is "partially unsound". As a public API this would + /// be unacceptable, but this is crate-private, and if you use this in + /// the most obvious and simplistic way it Just Works™. + /// + /// Note however that std specifically bypasses this lock, and uses + /// the `*_unsynchronized` backtrace APIs. This is "fine" because + /// it wraps its own calls to backtrace in a non-reentrant Mutex + /// that prevents two backtraces from getting interleaved during printing. pub fn lock() -> LockGuard { + // If we're the thread holding this lock, pretend to acquire the lock + // again by returning a LockGuard(None) if LOCK_HELD.with(|l| l.get()) { return LockGuard(None); } + // Insist that we totally are the thread holding the lock + // (our thread will block until we are) LOCK_HELD.with(|s| s.set(true)); unsafe { + // lazily allocate the lock if necessary INIT.call_once(|| { LOCK = Box::into_raw(Box::new(Mutex::new(()))); }); + // ok *actually* try to acquire the lock, blocking as necessary LockGuard(Some((*LOCK).lock().unwrap())) } } From 13963aec5cb9a6de6d04047e960a3146c4868245 Mon Sep 17 00:00:00 2001 From: Jubilee <46493976+workingjubilee@users.noreply.github.com> Date: Mon, 27 May 2024 15:16:35 -0700 Subject: [PATCH 23/26] Test with lld-compatible args (rust-lang/backtrace-rs#627) Rust on Linux has switched to using rust-lld by default, and it does not support the zlib-gnu or zlib-gabi arguments for --compress-debug-sections! Not surprising. It's... not GNU. Compensate for this by using zlib, which everyone supports. --- .github/workflows/main.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6ed2863cf..55e2d126f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -80,11 +80,7 @@ jobs: - run: cargo test if: contains(matrix.os, 'ubuntu') env: - RUSTFLAGS: "-C link-arg=-Wl,--compress-debug-sections=zlib-gabi" - - run: cargo test - if: contains(matrix.os, 'ubuntu') - env: - RUSTFLAGS: "-C link-arg=-Wl,--compress-debug-sections=zlib-gnu" + RUSTFLAGS: "-C link-arg=-Wl,--compress-debug-sections=zlib" # Test that, on macOS, packed/unpacked debuginfo both work - run: cargo clean && cargo test From 9f2b1e132065a6f2e4548421eaf50e0982d58a58 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 28 May 2024 00:37:34 +0200 Subject: [PATCH 24/26] Bump rustc-demangle version (rust-lang/backtrace-rs#624) --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 30f0452b4..23e01d6da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -147,9 +147,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "serde" diff --git a/Cargo.toml b/Cargo.toml index 7c1a92042..bb8847686 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ exclude = [ [dependencies] cfg-if = "1.0" -rustc-demangle = "0.1.4" +rustc-demangle = "0.1.24" # Optionally enable the ability to serialize a `Backtrace`, controlled through # the `serialize-serde` feature below. From 0147d56c5f32c4ea821f1f8b0d8d6da1e03047f9 Mon Sep 17 00:00:00 2001 From: klensy Date: Tue, 28 May 2024 01:49:00 +0300 Subject: [PATCH 25/26] cleanup dead_code for cpp_demangle (rust-lang/backtrace-rs#622) --- src/symbolize/mod.rs | 99 ++++++++++++++------------------------------ 1 file changed, 32 insertions(+), 67 deletions(-) diff --git a/src/symbolize/mod.rs b/src/symbolize/mod.rs index 3f5e2f1c5..9706835e6 100644 --- a/src/symbolize/mod.rs +++ b/src/symbolize/mod.rs @@ -292,32 +292,15 @@ cfg_if::cfg_if! { OptionCppSymbol(None) } } - } else { - use core::marker::PhantomData; - - // Make sure to keep this zero-sized, so that the `cpp_demangle` feature - // has no cost when disabled. - struct OptionCppSymbol<'a>(PhantomData<&'a ()>); - - impl<'a> OptionCppSymbol<'a> { - fn parse(_: &'a [u8]) -> OptionCppSymbol<'a> { - OptionCppSymbol(PhantomData) - } - - fn none() -> OptionCppSymbol<'a> { - OptionCppSymbol(PhantomData) - } - } } } /// A wrapper around a symbol name to provide ergonomic accessors to the /// demangled name, the raw bytes, the raw string, etc. -// Allow dead code for when the `cpp_demangle` feature is not enabled. -#[allow(dead_code)] pub struct SymbolName<'a> { bytes: &'a [u8], demangled: Option>, + #[cfg(feature = "cpp_demangle")] cpp_demangled: OptionCppSymbol<'a>, } @@ -327,6 +310,7 @@ impl<'a> SymbolName<'a> { let str_bytes = str::from_utf8(bytes).ok(); let demangled = str_bytes.and_then(|s| try_demangle(s).ok()); + #[cfg(feature = "cpp_demangle")] let cpp = if demangled.is_none() { OptionCppSymbol::parse(bytes) } else { @@ -336,6 +320,7 @@ impl<'a> SymbolName<'a> { SymbolName { bytes: bytes, demangled: demangled, + #[cfg(feature = "cpp_demangle")] cpp_demangled: cpp, } } @@ -380,65 +365,45 @@ fn format_symbol_name( Ok(()) } -cfg_if::cfg_if! { - if #[cfg(feature = "cpp_demangle")] { - impl<'a> fmt::Display for SymbolName<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some(ref s) = self.demangled { - s.fmt(f) - } else if let Some(ref cpp) = self.cpp_demangled.0 { - cpp.fmt(f) - } else { - format_symbol_name(fmt::Display::fmt, self.bytes, f) - } - } +impl<'a> fmt::Display for SymbolName<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Some(ref s) = self.demangled { + return s.fmt(f); } - } else { - impl<'a> fmt::Display for SymbolName<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some(ref s) = self.demangled { - s.fmt(f) - } else { - format_symbol_name(fmt::Display::fmt, self.bytes, f) - } + + #[cfg(feature = "cpp_demangle")] + { + if let Some(ref cpp) = self.cpp_demangled.0 { + return cpp.fmt(f); } } + + format_symbol_name(fmt::Display::fmt, self.bytes, f) } } -cfg_if::cfg_if! { - if #[cfg(all(feature = "std", feature = "cpp_demangle"))] { - impl<'a> fmt::Debug for SymbolName<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use std::fmt::Write; - - if let Some(ref s) = self.demangled { - return s.fmt(f) - } - - // This may to print if the demangled symbol isn't actually - // valid, so handle the error here gracefully by not propagating - // it outwards. - if let Some(ref cpp) = self.cpp_demangled.0 { - let mut s = String::new(); - if write!(s, "{cpp}").is_ok() { - return s.fmt(f) - } - } - - format_symbol_name(fmt::Debug::fmt, self.bytes, f) - } +impl<'a> fmt::Debug for SymbolName<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Some(ref s) = self.demangled { + return s.fmt(f); } - } else { - impl<'a> fmt::Debug for SymbolName<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some(ref s) = self.demangled { - s.fmt(f) - } else { - format_symbol_name(fmt::Debug::fmt, self.bytes, f) + + #[cfg(all(feature = "std", feature = "cpp_demangle"))] + { + use std::fmt::Write; + + // This may to print if the demangled symbol isn't actually + // valid, so handle the error here gracefully by not propagating + // it outwards. + if let Some(ref cpp) = self.cpp_demangled.0 { + let mut s = String::new(); + if write!(s, "{cpp}").is_ok() { + return s.fmt(f); } } } + + format_symbol_name(fmt::Debug::fmt, self.bytes, f) } } From 2e8b2bac3b9fd721ed6bb913e95023a98743eb18 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Mon, 27 May 2024 16:05:12 -0700 Subject: [PATCH 26/26] Cut 0.3.72 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 23e01d6da..9772e64ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,7 +32,7 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.72" dependencies = [ "addr2line", "cc", diff --git a/Cargo.toml b/Cargo.toml index bb8847686..9dcc54a40 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "backtrace" -version = "0.3.71" +version = "0.3.72" authors = ["The Rust Project Developers"] build = "build.rs" license = "MIT OR Apache-2.0"