Skip to content
This repository has been archived by the owner on Sep 12, 2024. It is now read-only.

Non allocating / low memory usage backtrace printing interface #35

Open
yaahc opened this issue Mar 15, 2021 · 9 comments
Open

Non allocating / low memory usage backtrace printing interface #35

yaahc opened this issue Mar 15, 2021 · 9 comments

Comments

@yaahc
Copy link
Member

yaahc commented Mar 15, 2021

Right now std has proposed stabilizing a very minimal interface for capturing and printing Backtraces. However, internally it does not use this same interface in it's own panic hook. Internally, instead of capturing a Backtrace object and then printing it std directly invokes a function that prints the backtrace without capturing or resolving frames in advance (source). This interface apparently uses much less memory (does it allocate heap memory at all?).

Other contributors to the project have expressed a desire for a lightweight backtrace printing interface they can use from signal handlers and the like (source). The above interface doesn't seem to work in this specific scenario, but we may want to look into what would be needed to print a backtrace from a signal handler, and in the future possibly expose alternate interfaces to printing backtraces that could work in these constrained environments.

@burdges
Copy link

burdges commented Mar 15, 2021

Can error types be !Send and/or !Sync?

@yaahc
Copy link
Member Author

yaahc commented Mar 16, 2021

Can error types be !Send and/or !Sync?

yes, how does that apply here?

edit: actually, yes depending on what you mean by "be !Send". If you're referring to negative trait bounds then no, but if you mean can errors not implement Send or Sync and still implement the Error trait then absolutely, though many parts of the ecosystem assume that all error types are Send + Sync + 'static, so we advise against making errors that aren't Send/Sync/'static, or at least suggest that you have a conversion method for getting an owned + Send + Sync version of those errors.

@Amanieu
Copy link
Member

Amanieu commented May 14, 2021

I just published mini-backtrace which allows capturing backtraces on no_std/embedded targets. It does not use any dynamic memory allocation, and resolving symbol names & line numbers is done offline using addr2line.

Internally it uses LLVM's libunwind built with special flags and stripped of all OS/libc dependencies.

@yaahc
Copy link
Member Author

yaahc commented May 14, 2021

That's amazing @Amanieu, do you think the approach used in mini-backtrace could eventually be applied upstream to std::backtrace::Backtrace?

@Amanieu
Copy link
Member

Amanieu commented May 14, 2021

Not really, unwinding/backtraces fundamentally relies on some system-level support to locate unwinding information for the current binary. mini-backtrace compiles its own libunwind with -D_LIBUNWIND_IS_BAREMETAL which causes it to use the special symbols __exidx_* to locate unwinding metadata in memory. This requires using special linker scripts to set up and only works for the main executable, not any shared libraries.

Resolving symbols and line numbers requires reading debuginfo which is not loaded to memory, which is not possible in no_std. mini-backtrace just punts symbol resolution to an offline step.

@thomcc
Copy link
Member

thomcc commented Apr 7, 2022

It would also be desirable to use something like this in signal handlers. This is sometimes1 supported by C/C++ backtrace libs (a concrete example is that abseil's has it) since otherwise it's dubious (very unsafe) to use in cases like a segfault handler that tells you where the bad pointer use happened.

It may be more trouble than it's worth though... It is certainly less critical for Rust, where bad pointer dereferences are not nearly as common.

Footnotes

  1. I almost said commonly here, but it's not clear to me if its actually commonly supported, or if people just commonly do it anyway. (Realistically, you can get away with doing a lot of signal-unsafe things in signal handlers...)

@sfackler
Copy link
Member

sfackler commented Apr 7, 2022

I'm currently using the libunwind project to backtrace in a signal handler since it's the only standalone one I'm aware of that claims to be async-signal safe. It would be amazing if the standard version offered that capability.

@Amanieu
Copy link
Member

Amanieu commented Apr 7, 2022

I'm currently using the libunwind project to backtrace in a signal handler since it's the only standalone one I'm aware of that claims to be async-signal safe.

It's not because it uses dl_iterate_phdr from the dynamic linker to locate unwinding information. This function takes locks and allocates memory.

@sfackler
Copy link
Member

sfackler commented Apr 8, 2022

Yeah their documentation seems overly optimistic. Abseil's may be more accurate, but it appears to rely on frame pointers which is not really a realistic option unless you're building your entire userspace...

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants