Live data from Hacker News

Show HN: Using C++23 to get proper crash logs in C++ programs

github.com

31–40 of 95 posts

Re: Show HN: Using C++23 <stacktrace> to get proper crash logs in C++ programs

#31

Earlier quoted context omitted.

> once collected, stack traces are just regular object that can be passed around thread as other object. > It's possible that some implementation have references to some stack addresses (like for example the address of a function parameter), in which case you would need to serialize the stack trace before storing them/ moving then another thread. So which of these two mutually exclusive options is it? As I understand…

When I debug multithreaded programs, the stacktrace of a breakpoint usually ends somewhere in a worker thread. What I want is that the worker thread's stacktrace part is replaced by the one who put the work into it. Kinda like the program wasn't multithreaded at all.

if you actually wanted to you could probably wrap thread to pass the stacktrace of the spawning thread into the worker thread whenever you spawn a thread and then output that upon a crash as well. the library seems pretty simple and flexible.

Re: Show HN: Using C++23 <stacktrace> to get proper crash logs in C++ programs

#32

Reliable in-process crash reporting is exceptionally difficult. The code must be fully async-safe, which means you cannot use . You also cannot acquire mutexes, use any of the standard allocators, etc etc etc.

The best way I've found is - patching LLVM's libunwind to make it fully async-signal safe, and sending the stack trace to another thread for symbolization. This is implemented in ClickHouse.

1. Can you link to that?

2. Have these changes been offered as patch for libunwind or boost::stacktrace?

Re: Show HN: Using C++23 <stacktrace> to get proper crash logs in C++ programs

#33

Reliable in-process crash reporting is exceptionally difficult. The code must be fully async-safe, which means you cannot use . You also cannot acquire mutexes, use any of the standard allocators, etc etc etc.

What is async-unsafe in using ` `? As for not using standard allocators - not a problem, just have a fixed area set aside as a buffer for crash reporting. Yes, it might not fit an extremely long report, but it's not that much of an issue.

It’s not guaranteed to be async-safe. From the C++ proposal (P0881R7):

> Note about signal safety: this proposal does not attempt to provide a signal-safe solution for capturing and decoding stacktraces. Such functionality currently is not implementable on some of the popular platforms.

https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p08...

[edit] Replying here, because HN is doing its occasional obnoxious rate-limiting of replies:

Signal-safe and async-safe are effectively the same thing, and “async-safe” absolutely isn’t the same thing as “thread-safe”.

A code path that acquires a mutex can be thread-safe; that’s absolutely not async-safe.

If boost implemented a fully async-safe stack unwinder, complete with DWARF expression support, Apple compact unwind encoding support, and all the other features required across platforms, then good for them — but that’s not what is guaranteed to provide, and such a thing is still not sufficient to implement anything but the most barebones portion of a real crash reporter.

Re: Show HN: Using C++23 <stacktrace> to get proper crash logs in C++ programs

#34

Earlier quoted context omitted.

> once collected, stack traces are just regular object that can be passed around thread as other object. > It's possible that some implementation have references to some stack addresses (like for example the address of a function parameter), in which case you would need to serialize the stack trace before storing them/ moving then another thread. So which of these two mutually exclusive options is it? As I understand…

When I debug multithreaded programs, the stacktrace of a breakpoint usually ends somewhere in a worker thread. What I want is that the worker thread's stacktrace part is replaced by the one who put the work into it. Kinda like the program wasn't multithreaded at all.

Ah. I guess you can capture the stack trace at task creation point, then stitch together a new stack trace by replacing the generic common prefix of your worker thread trace with the task creation one.

But you can't use the basic_stacktrace container itself as it is immutable and not constructibe from a range, so you have to roll your own. You should be able to use the stacktrace_entries though.

Most importantly, I expect that capturing a stacktrace is quite expensive, so you might not be able to do it at task creation time, and it is too late to do it later. Maybe you want this only in debug mode.

Note I haven't actually tried any if this, it is just guesswork.

Re: Show HN: Using C++23 <stacktrace> to get proper crash logs in C++ programs

#35
post #20

There are parts of C++ standard library that no one should ever use. The examples are: regex, iostreams, locale... My main concern - this can also become such a dead weight.

What's wrong with std::regex? Seems to work fine for me. And iostreams - they're not great. Bad programming UI, poor performance, etc. Issues abound. But should you never use them? What do you use instead? *printf methods have lots of issues too. And so does depending on Boost::format. And so does writing your own Logger/wrapping code (which is what everyone does AFAICT). locale is bad though

> What do you use instead [of std::iostream]?

This is what I want to know. Having come from C to C++, iostreams were a big improvement over the "strings" and print functions of C. I even extended a base iostream class to have a "teebuf" logger, that could output to multiple streams and had the standard logging levels.

It's been a while since I last had mastery of C++, but I'd like to hear what is as portable and better than iostreams.

Re: Show HN: Using C++23 <stacktrace> to get proper crash logs in C++ programs

#36

Earlier quoted context omitted.

From what I’ve heard, std::regex is notoriously inefficient (lots of memory allocations, no allocator support). But I’ve never used it myself.

oh yeah C++ regex is stupidly inefficient, like "python is faster" inefficient. I tried to use it for text replacements and pretty much immediately abandoned it

Apparently typical implementations of std::regex are inefficient like "'popen("perl..")' is faster" is inefficient!

I thing boost::regex is significantly faster although not particularly fast

Re: Show HN: Using C++23 <stacktrace> to get proper crash logs in C++ programs

#37

Earlier quoted context omitted.

> once collected, stack traces are just regular object that can be passed around thread as other object. > It's possible that some implementation have references to some stack addresses (like for example the address of a function parameter), in which case you would need to serialize the stack trace before storing them/ moving then another thread. So which of these two mutually exclusive options is it? As I understand…

When I debug multithreaded programs, the stacktrace of a breakpoint usually ends somewhere in a worker thread. What I want is that the worker thread's stacktrace part is replaced by the one who put the work into it. Kinda like the program wasn't multithreaded at all.

I think what you looking for is "task tracing" not really stack tracing. The relationship between the task (like where was a task added in the thread pool) are not reflected in the stacktrace the way you want them. To address those, you need to have special handshake between the debugger and your task api. You can also instrument the "add_task" function call to log every time a task is added to you queue and do some some offline stack stiching.

Re: Show HN: Using C++23 <stacktrace> to get proper crash logs in C++ programs

#38
post #29
post #4

Earlier quoted context omitted.

What's the benefit of in-process crash reporting compared to just using something like crashpad/breakpad? To the extent that in-process crash reporting is even possible... seems the most common class of crashes would be entirely unrecoverable.

Ease of integration, because having literally anything is typically better than nothing. Honestly Crashpad isn't fun to integrate unless you use a fork like backtrace's (which adds CMake support), which I think doesn't help. I don't know of any alternatives. A version of Crashpad or something like it with a single turnkey server for database dumps, a one-line "defaults are good enough" integration, would be a real gr…

I found Sentry's crash reporting (which uses crashpad) simple enough to configure into an existing CMake build within an afternoon.

Building Sentry/crashpad from source in a few lines of CMake: https://github.com/ArmageddonGames/ZQuestClassic/commit/3471...

And a few lines in the main function: https://github.com/ArmageddonGames/ZQuestClassic/commit/3471...

Re: Show HN: Using C++23 <stacktrace> to get proper crash logs in C++ programs

#39

Earlier quoted context omitted.

I am not sure if i understand the question correctly. But once collected, stack traces are just regular object that can be passed around thread as other object. It's possible that some implementation have references to some stack addresses (like for example the address of a function parameter), in which case you would need to serialize the stack trace before storing them/ moving then another thread.

> once collected, stack traces are just regular object that can be passed around thread as other object. > It's possible that some implementation have references to some stack addresses (like for example the address of a function parameter), in which case you would need to serialize the stack trace before storing them/ moving then another thread. So which of these two mutually exclusive options is it? As I understand…

> So which of these two mutually exclusive options is it? As I understand it, that was the question.

Well the stack_entry/stack_trace object can be moved around between thread, as in the object itself is copyable and movable. However, the handle_type is implementation defined, so it might be the case that extracting the information out of the object only works on the producing thread.

Re: Show HN: Using C++23 <stacktrace> to get proper crash logs in C++ programs

#40

Earlier quoted context omitted.

When I debug multithreaded programs, the stacktrace of a breakpoint usually ends somewhere in a worker thread. What I want is that the worker thread's stacktrace part is replaced by the one who put the work into it. Kinda like the program wasn't multithreaded at all.

Ah. I guess you can capture the stack trace at task creation point, then stitch together a new stack trace by replacing the generic common prefix of your worker thread trace with the task creation one. But you can't use the basic_stacktrace container itself as it is immutable and not constructibe from a range, so you have to roll your own. You should be able to use the stacktrace_entries though. Most importantly, I e…

Exactly this. I didn't try this, and I suppose that some low level pointer rewriting would be necessary to do this. I'm not sure if it's expensive though, maybe you can replace the pointers without resolving the stacktrace.
Post reply on HN