Why is it that even though Github or what ever has cutsie unicorns (or whatever it is) as error messages it feels fake and contrived while this define just feels like some random dude at MS naming it before going off to write Solitaire?
For those curious about WIN32_LEAN_AND_MEAN - it reduces compile time by not auto-including a number of windows headers: https://devblogs.microsoft.com/oldnewthing/20091130-00/?p=15...
Its also my favorite btw.
One example was min and max - Win32 includes those which messes with trying to use std::min and std::max.
https://github.com/Ardour/ardour/blob/master/libs/pbd/stackt...
(2 different implementations, one for POSIX-y systems with the execinfo.h header, and one for Windows)
The demange() function is elsewhere.
The examples are: regex, iostreams, locale...
My main concern - this can also become such a dead weight.
//a decent amount of this was copied/modified from backward.cpp (https://github.com/bombela/backward-cpp)
The license on the other side of that link: The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.The code must be fully async-safe, which means you cannot use <stacktrace>. You also cannot acquire mutexes, use any of the standard allocators, etc etc etc.
> 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 it, that was the question.
I also quite doubt that std::mutex, and even more so std::condition_variable are guaranteed to be signal safe.
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
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.
2. Some existing implementations have efficiency issues, e.g. performing many allocations.
3. It is claimed (e.g. by Titus Winters) that the ABI of std::regex is problematic, and without breaking it, the implementations cannot be good enough
See these points and others at:
https://www.reddit.com/r/cpp/comments/e16s1m/what_is_wrong_w...
In my experience, stdlibc++ <regex> is VERY slow, especially on debug builds. We are using g_regex instead, which in turn uses pcre2.
> And iostreams
<iostream> achieves too little with too much code. We instead use:
std::cout << fmt::format(...);
for simple output, loguru[1] for everything else. I feel like the fmt grammar/mini-language is both nicely extensible and has hit the expressiveness sweet spot -- not too verbose (iostreams) nor too terse (printf).I also like that fmt has helpers for pointers (fmt::ptr), enums (fmt::underlying) and arrays (fmt::join). It's both easy on the eyes and feels consistent.
2. Have these changes been offered as patch for libunwind or boost::stacktrace?
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.
> 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 <stacktrace> 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.
To the extent that in-process crash reporting is even possible... seems the most common class of crashes would be entirely unrecoverable.
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 great thing to see.
There were multiple steps:
1. Avoid using malloc/free inside libunwind.
2. Avoid using FDECache that required a mutex.
3. Avoid using dl_iterate_phdr (a mutex inside libc).
4. Protection from dereferencing wrong pointers due to incorrect unwind tables.
Most of the changes were integrated to libunwind, but not everything. Example: https://bugs.llvm.org/show_bug.cgi?id=48186
2. The boost::stacktrace library (on which the standardization was mostly based IIANM) has a `safe_dump_to()` function for these cases.
See here: https://github.com/boostorg/stacktrace/blob/develop/include/...
I thing boost::regex is significantly faster although not particularly fast
... fmt::print(...); ``` Instead, to save that potential double buffer copy.
The good news is also that it has no effect. :)
You can verify this for yourself by grepping the Visual Studio headers for VC_EXTRALEAN and WIN32_EXTRA_LEAN.
> VC_EXTRALEAN defines WIN32_LEAN_AND_MEAN and a number of NOservice definitions, such as NOCOMM and NOSOUND.
> https://gamedev.net/forums/topic/367942-win32_lean_and_mean-...
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.
You should be able to, for example, collect the stacktace on one thread, transport it to another and print it.
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.
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...
You add one C file and 6 lines of code in `main()`, and you can do this in pretty much any programming language with a tiny extra bit of glue. It takes 3 minutes to do this in any C/C++ codebase of mine. It is build system agnostic and works immediately, with zero outside deps. It's something, and that's better than nothing, in practice. So people reach for that. I reach for it. And not just because I wrote it.
I want to be clear: Crashpad is 10000x better than mine in every way, except this one way. And I really wish it wasn't. To add onto this, I really don't like CMake for example, so this problem isn't just a "well I like my thing." I want something that will also work in my Java programs, or Rust programs, for instance! Sometimes they crash too. I don't need to add any dependencies except like 2 or 3 C function calls, which almost every langauge supports with a native FFI out of the box. The friction is extremely low.
I'm reminded of something Yann Collet once said about the design of zstd, and getting people to adopt new compression technology. If you make a compressor and it's better than an alternative in one or more dimensions, but worse in another (size, decompressor speed), then friction is actually significantly increased by that one failure. But if you make it better in every dimension -- so it gives an equal ratio and compression and decompression are always better than alternatives -- the friction is eliminated and people will just reach for it. Even though you only did worse in one spot, people find ways to make it matter. It really makes people think twice. But if it's always better, in every way, then using and reaching for it is just instinctive -- it replaces the old thing entirely.
So that's what I really wish we had here. I think that's what you would need to see a lot better crash handling and reporting become more widely used. There needs to be a version of Crashpad, or any robust out of process crash collector, that you can just drop into any language and any build system with a little C glue (or Rust! Sure! Whatever!) in 5 minutes and it should have a crash database server and crash handler process which should instantly work for most uses.
This all feels like a failure of our modern OSes - why must the application layer know how to report on when it crashes? It seems like functionality that the OS should provide! Instead, we're stuck reaching for these random extensions solving the same problem in the same way everywhere - or, if you're lucky, this gets provided by the language framework for "free" to application developers (but not the language developers).
They are not. Use sem_t for signaling.
edit: also even if they where, the signal handler might wait forever for a mutex owned by the blocked thread.
You're right about mutex & cv in the general case though
FWIW I've run into malloc self dreadlocks due to rare signals plenty of time :(. In production workloads.
Maybe it shouldn't be there and some better thing should be there, but given it exists ... as long as one is aware of alternatives using it is fine.
std::regex only sucks because the developers of gcc and clang never bothered to optimize it. (Too much work and they have other stuff to worry about.)
There's generally not all that much stdc++ specific optimisation stuff in clang. There might be parts of regex that are worth implementing as compiler intrinsics, that seems to be the existing pattern for making bits much faster.
The really heavy lifting you want for regex is to partially evaluate and split them. They're a separate language unto themselves and benefit from being optimised as such. There's nowhere ideal in the clang/llvm pipeline to do that though.
That's the only real reason why std::regex is slow.
- <iostream> makes localization more difficult, compared to printf (localizing <iostream> code is beyond awful)
- <iostream> makes thread safety more difficult, compared to printf (it is safe to printf/fprintf from multiple threads, simultaneously, without any extra work)
- The <iostream> operator overloading syntax is bad (my sense is that the operator overloading abuse in <iostream> was a contributing factor for why Java doesn't allow operator overloading)
- Streams in <iostream> are stateful, and it's easy to accidentally leave them in the wrong state (radix, padding, field width, etc)
- Performance of <iostream>, out of the box, is mediocre (to get decent performance, you need to change some defaults)
The main advantage of <iostream> was that it provided type safety, but IMO that advantage has long since been irrelevant. You get type safety with std::printf, with most compilers, assuming you enable -Wformat on GCC or similar options in other compilers.
The only remaining advantage of <iostream> is that you can overload operator<<. I don't think that's much of an advantage, especially weighed against the numerous disadvantages.
Using std::printf is better and more portable. Libfmt is also better and more portable, and it is now part of the standard library as std::format.
https://www.moria.us/articles/iostream-is-hopelessly-broken/
In an obnoxious way. The first code someone will see of a new language is often 'hello world'. In C++, 'hello world' is an advertisement for the fact that operator overloading exists.
it's the coolest part
About 6-7 years ago back when my employer was running code compiled with gcc-4.4.7 and running it on Linux 2.6.32 boxes even though it was pretty old even back then, it took me a lot of convincing the company to give libfmt a try.
It was such a boost to developer happiness. People were literally overjoyed, writing to me on Slack how much of a pleasure string formatting has become.
Have a look at fmtlib. The interface is more like printf, but type safe and format strings are parsed at compile time. I believe it’s what std::format is based on, which could also be an option for you depending on how recent your compiler/language version is.
See, I don't believe that's an improvement. Having used printf in C, I was relieved to be able to "redirect" whatever to a stream, and not care about whether it should be "%d" or "%02f" or even if it was a struct/class.
On top of this, treating files as streams, strings as streams, or even extending streams to make a tee-stream[0] all seem clunkier to me with a printf like system.
Maybe fmt fixes these problems, I don't know. But I feel a lot of people don't like iostreams because they have some form of Stockholm syndrome with printf.
[0] - https://wordaligned.org/articles/cpp-streambufs#tee-streams
Yeah, it looks like you did a lot of guesswork in that comment, and a lot of those guesses were inaccurate. Not really trying to be hostile here, but you did acknowledge that you were unfamiliar with std::format.
The part that fmtlib / std::format has, which is printf-like, is the idea of having a format string and arguments, rather than having a bunch of separate, piecemeal strings.
// Old printf code, works ok for most people
std::printf("failed to clone %s from %s", target, src);
// <iostream>
std::cout << "failed to clone " << target << " from " << src;
// New std::format / fmtlib
std::print("failed to clone {} from {}", target, src);
You can see that you don't need to remember what kind of format specifier you need. This is C++, and that kind of problem is solved with overloading.The std::print interface can work equally well with FILE or std::ofstream, or whatever you want. This is C++, and so you can just use a templated output iterator—or one of the overloads that creates one automatically.
There are a lot of problems with <iostream>. I think it’s telling that lots of languages have copied printf, but nobody (or almost nobody) thought <iostream> was good enough to copy. There are just too many serious design flaws with <iostream>. It would be one thing if <iostream> were just annoying to use, but it poses problems for localization, thread-safety, accidental misuse through its statefulness, and its operator overloading syntax is bad.
FWIW, I have waaaay more experience with iostreams than printf. I once wrote a replacement for most parts of std::ostream purely because I had a logging system that was loosely based on log4cxx (which is based on iostreams) and I needed much faster formatting.
Right now I'm in the process of switching to a different logging system that uses fmtlib. I can say that I really, really do not miss the extreme verbosity of iostreams at all. The statefulness I could take or leave, although on balance I'd say it's usually more of a negative. Thankfully I don't have to give up type safety or extensibility.
As for treating files/strings/whatever as streams--my impression of fmtlib is that it's concerned primarily with formatting, which frankly I'm fine with. It can write to an in-memory buffer or to a FILE* or to a std::ostream, which covers pretty much all of my needs. Given the performance of iostreams (lots of virtual method calls) I never really saw the point of using it as a more generalized 'streaming' interface, even knowing that it's possible.
However, printf and its ilk get it right; presentation is a property of the context in which the entity is to be presented, not of the entity itself. You can kvetch about the markup syntax, or the type safety issues the C implementation has, but the architecture is fundamentally correct.
It's Bjarne (Stroustrup)'s pet feature. You'll notice that many expert practitioners of C++ write std::println("Hello, world"); or similar for a canonical C++ 23 Hello World, but Bjarne pointedly still writes it with std::cout and the iostream operator overloads.
Now that Bjarne is back at Columbia teaching, there's a risk he'll infect impressionable young people with this nonsense, COMSW4995 was not an intro class and I suspect Bjarne's jetsetting makes it impractical to teach such a class, so this risk is small but not zero.