Libunwind also works great in this context. For some cases I even found it to
work much better than backtrace. It also has a signal-safe functions that
facilitate implementation of stack printing on crash.
I work with projects where stack traces are added automatically to exceptions
during throw. It works quite well, and in fact I would disagree with author on
some of his points:
- stack trace not representative of source code, due to optimizations -
unwinding information is consistent with what you have in a source code, and
compiler optimization don't change that (i.e., it would be a compiler bug if
it did, see any design document about debugging information, for example in
LLVM / Clang).
- throw expression is not a place where the problem is - that is of course true
in general, but how much more useful is stack trace indicating code path
where exception have been thrown, than merely a type of exception. Name of
function which have thrown an exception is also a good start, but of limited
value for some common utility functions.
- memory allocation - dynamic memory allocation could be problematic, but
storing stack trace in exception object itself is quite simple and avoid this
problem altogether.
This sort of thing drives me crazy sometimes. Why can't we have a high level assembly language which can represent the code that's executing. Right now I have the choice of either looking at the code, which can be wrong, or looking at assembly, which is hard to associate with the code. Why can't I look at annotated assembly which tells me exactly which part of the code it corresponds to?
> Why can't I look at annotated assembly which tells me exactly which part of the code it corresponds to?
Because modern optimizations make that impossible. (How do you represent a statement that GVN eliminated, for example?) Not doing those optimizations would make code unacceptably slow.
But an issue is still that in the handler (catch clause), the stack has unwound, so if you want to access the stack trace "after the fact", you will have to do some work when throwing the exception.
For many common ABIs, unwinding the stack is relatively cheap compared to decoding the debug info to figure out how to unwind the stack. If you have frame pointers, it's especially cheap -- you're walking a 20 element linked list.
To recap, if you want to implement your own exceptions in C++ with the stack trace in the same way as Java or C# do, that's good fun.
Just use Google Breakpad. For Objective-C, you'll probably do better with PLCrashReporter (or possibly KSCrash) which can reliably unwind at the time of the crash because of certain assumptions it can make about ObjC binaries that the more general Breakpad does not make. (Breakpad just captures the stacks to a minidump, which you then unwind later using symbol files generated from your binaries.)
you usually need to allocate a piece of memory in the heap
Breakpad preallocates. The ObjC (Mac, iOS) handler included with Breakpad (should you go that route) goes so far as to mprotect the preallocated memory to help protect it from memory smashers.
None of this is perfect, but I'd rather have stack traces than not. It's also useful to have a breadcrumb mechanism in the app to include with the stack trace.
Back in 2001, when VS6 couldn't even parse templates correctly, I was making games on Linux but wanted them to run on Windows and Mac too.
I also wanted stack traces in exceptions (or being able to get them at any time, really) and I wanted to make them encrypted, to avoid giving away the internal structure of our game and engine code.
The solution I came up with was to have a global array representing the stack trace, a macro that would create a small scoped object which pushed a new "stack trace" entry on creation and popped it on destruction, and a script that would add a call to this macro to the beginning of each method with any payload I wanted -usually the encrypted filename, line and signature of the method, but it was possible to append e.g. parameter values as well.
Since these strings were compile time constants, this whole thing was surprisingly cheap, and worked great for over a decade.
Most of the reasoning here seems to be based on 1) that "out of memory" is the only exception worth talking about, and 2) the only thing you want to do is abort the program at that point.
I don't think either of these are true. Some libraries make liberal use of exceptions, as a design decision. If your text editor tries to open an enormous file, you don't want it to crash, you want it to deallocate all of the memory it consumed for that file and then fall back with an error message.
I don't think the point about inlining is reasonable either: I wouldn't expect a fully optimised build to give me a full stack trace, that is what debug builds are for.
>If the exception is meant to signal the fact that the memory is finished, where are we allocating the stack trace?
If this is really a concern, allocate some memory at the start of execution that you can use in the event of a crash.
Unless you have carefully configured your OS, 'out of memory' exceptions are essentially worthless. This is because most systems work using 'optimistic' memory management, where it is not known (or checked) whether there is enough free memory available at the time of the malloc() call. The problem comes later, at any time when a random instruction tries to access the memory and the OS finds that it has no RAM available.
Agreed; in my line of work (mobile games) an out of memory exception is the least useful, because the place that threw is not necessarily in the offending system that ate all of the memory.
Getting stack traces for other exceptions IS useful - our code is full of assertions that throw when invariant assumptions are violated, and knowing the stack trace is useful for tracking down what system is misbehaving.
It's not perfect because all the destructors for your stack allocated objects have run. So for example, any std::string on the stack will be gone, but any pointers to structures on the heap are still intact.
In addition, just knowing what the stack was is invaluable in debugging even if you don't have the values of every variable.
It's a huge pain that you can't get that under linux.
Like the article, but I'm really not digging that style used for inline code snippets. Just changing font face and color a bit seems like a proven solution to me. Doing that but also adding ⌈characters⌋ around it makes it hard to read. At least for me.
Same feelings here: nice post but bad typography. To the author and anybody writing their own CSS: please use line spacing to make it easier to get the starting point of the next long line of text. See https://www.w3.org/TR/WCAG20-TECHS/C21.html and, believe me, it doesn't impact only "people with cognitive disabilities".
There are functions that can capture or print stack traces, such as the backtrace() family on OS X (which has a "man" page) or just the "pstack" command on Linux. It is very useful to have a function in your code base that invokes one of these on demand.
Then you can do interesting things like print a stack trace at a "throw" point if you suspect a problem, or capture a trace into an exception base class in debug modes for printing at catch points, or even as a form of non-crashing assertion to log traces whenever unexpected conditions arise.
It's true that exceptions in C++ are more expensive than in other languages, often even in absolute terms, but that has nothing to do with problem at hand.
In GC'd language, implementing exceptions by simple non-local exit to catch/finally block is perfectly viable implementation strategy. It does not work so well in C++, where are implicit finally blocks that call destructors of local variables almost everywhere. To some extent this feature could be abused to produce stack-trace during the unwinding (but that necessarily involves injecting code to all functions in the program).
On the other hand, CL/Smalltalk-style condition systems sidestep this issue completely, by running the handler code before unwinding the stack. Windows' SEH allows you to do the same thing. And IIRC even in plain C++, handler for completely unhandled exception (that by default involves call to abort()) runs without stack unwinding (thus something along the lines of std::set_terminate (__gnu_cxx::__verbose_terminate_handler) gives you stacktraces for unhandled exceptions).
I'd rather have a core dump than a stack trace. There's so much more information in a core dump. The stack is there as well, but having all live variables in the program, all loaded code, and all process state makes it so much easier to debug what's going wrong.
Some ffis do this to present C++ stack traces to their host languages.
If variables/frames are optimized out, then yes, you can't display their contents. But anyone that has used gdb already knows this...