Live data from Hacker News

C++ Exceptions: Under the Hood (2013)

monkeywritescode.blogspot.com

21–30 of 116 posts

Re: C++ Exceptions: Under the Hood (2013)

#21
post #15

Working with and implementing C++ exceptions for 30 years now, including implementing exception handling for Windows, DOS extenders, and Posix (all very different), and then re-implementing them for D, I have sadly come to the conclusion that exceptions are a giant mistake. 1. they are very hard to understand all the way down 2. they are largely undocumented in how they're implemented 3. they are slow when thrown 4.…

What do you think of languages that use sum types for error handling, but can still unwind in a few scenarios? Reasonnable compromise, or should we get rid of all unwinding always? And if so, do we abort() or do we ask users to handle any and all possible errors.

Rust is one such language. I wrote a bit about exception safety in Rust here: https://users.rust-lang.org/t/c-pitfalls-hard-to-avoid-that-...

In short, while the problem is mitigated somewhat compared to C++, it's still one of the most common causes of bugs in unsafe Rust code.

Rust programs can choose to abort on all panics, rather than unwind. Firefox does this, for example.

Re: C++ Exceptions: Under the Hood (2013)

#22
> When the personality function doesn't know what to do it will invoke the default exception handler, meaning that in most cases throwing from a nothrow method will end up calling std::terminate.

This is an interesting tidbit that cost me a week of debugging recently - a try/catch block at the top of the call stack wasn't catching an exception.

We set up an exception handler that calls main in a try/catch block, so that any thrown exceptions can be caught, processed, and dispatched to our crash-logging system.

But destructors are marked nothrow by default. So we had a case where an object was destroyed, and about 10 levels down from its destructor some other system threw an exception, intending it to be caught by the top-level catch block.

But during stack unwinding we passed through the nothrow destructor and std::terminate got called before unwinding got to the top-level try/catch.

Re: C++ Exceptions: Under the Hood (2013)

#23

Working with and implementing C++ exceptions for 30 years now, including implementing exception handling for Windows, DOS extenders, and Posix (all very different), and then re-implementing them for D, I have sadly come to the conclusion that exceptions are a giant mistake. 1. they are very hard to understand all the way down 2. they are largely undocumented in how they're implemented 3. they are slow when thrown 4.…

P.S. I implemented Structured Exception Handling for Win32, with help from a couple very smart people. Microsoft completely changed it for Win64, and the documentation on it is completely unhelpful to nonexistent.[1] I simply gave up on it. D on Win64 uses the exception handling mechanism I invented for the 32 bit DOS extender from the old Zortech days. It works fine, except that it cannot interact with C++ exception…

Ah, Zortech C++. That indeed brings back some memories.

Walter, what do you think about Herb Sutter "new" C++ exceptions (which is basically about throwing an int/a word) ?

Re: C++ Exceptions: Under the Hood (2013)

#24

Earlier quoted context omitted.

> they are slow when not thrown I thought the not-thrown case was pretty much zero-cost, at least in newer versions of Clang... How much of a slow down are we talking here?

The main reason is the optimizer abandons trying to figure out flow-of-control when half the expressions can throw and present a path to the catch blocks. Furthermore, this all inhibits en-registering variables, because exception unwinding doesn't restore registers. If you want your code to be fast, use 'nothrow' everywhere. I don't know about newer versions of Clang, but I recall Chandler Carruth mentioning that LLV…

Java JITs are considerably more advanced than this. It's expensive to put in all the additional control flow edges to model exceptions, but once done, control and data flow analyses just work, as well as loop optimizations, code motion, inlining, register allocation--all of it "just works" (TM). Then you have to spit out a metric crapton of metadata to allow searching for the correct handler at runtime, but that's the slow path.

All of that is to say that Java try blocks do not have any direct dynamic cost when exceptions are not thrown.

Even throwing exceptions and catching them locally in Java can be fast. If everything gets inlined into one compilation unit and the exception object is escape analyzed, HotSpot will absolutely just emit a jump.

Not that I disagree with your overall point--Virgil just doesn't have exceptions--but from your description here it just sounds like your compiler is far behind the state of the art in terms of optimizing exception-heavy code.

Re: C++ Exceptions: Under the Hood (2013)

#25

Earlier quoted context omitted.

P.S. I implemented Structured Exception Handling for Win32, with help from a couple very smart people. Microsoft completely changed it for Win64, and the documentation on it is completely unhelpful to nonexistent.[1] I simply gave up on it. D on Win64 uses the exception handling mechanism I invented for the 32 bit DOS extender from the old Zortech days. It works fine, except that it cannot interact with C++ exception…

Ah, Zortech C++. That indeed brings back some memories. Walter, what do you think about Herb Sutter "new" C++ exceptions (which is basically about throwing an int/a word) ?

If there's anyone who can think of a better way, it's Herb. I'd take anything he has to say about C++ very very seriously.

Re: C++ Exceptions: Under the Hood (2013)

#26

Working with and implementing C++ exceptions for 30 years now, including implementing exception handling for Windows, DOS extenders, and Posix (all very different), and then re-implementing them for D, I have sadly come to the conclusion that exceptions are a giant mistake. 1. they are very hard to understand all the way down 2. they are largely undocumented in how they're implemented 3. they are slow when thrown 4.…

Can you describe your ideal error handling mechanisms? Or at least other mechanisms that feel more correct?

Re: C++ Exceptions: Under the Hood (2013)

#27
post #24

Earlier quoted context omitted.

The main reason is the optimizer abandons trying to figure out flow-of-control when half the expressions can throw and present a path to the catch blocks. Furthermore, this all inhibits en-registering variables, because exception unwinding doesn't restore registers. If you want your code to be fast, use 'nothrow' everywhere. I don't know about newer versions of Clang, but I recall Chandler Carruth mentioning that LLV…

Java JITs are considerably more advanced than this. It's expensive to put in all the additional control flow edges to model exceptions, but once done, control and data flow analyses just work, as well as loop optimizations, code motion, inlining, register allocation--all of it "just works" (TM). Then you have to spit out a metric crapton of metadata to allow searching for the correct handler at runtime, but that's th…

Java has a far, far more restricted view of exceptions than C++ and D have,[1] and hence more opportunities for optimization. I did implement exceptions in the Javascript compiler I implemented 20 years ago, and they're a cakewalk compared to C++. I also implemented a native Java compiler, including EH.

As for clang, see what Chandler said. But maybe things have changed in the last couple years.

[1] for example, Java doesn't have objects on the stack that need their destructors run. That's a massive simplification.

Re: C++ Exceptions: Under the Hood (2013)

#28
post #24

Earlier quoted context omitted.

The main reason is the optimizer abandons trying to figure out flow-of-control when half the expressions can throw and present a path to the catch blocks. Furthermore, this all inhibits en-registering variables, because exception unwinding doesn't restore registers. If you want your code to be fast, use 'nothrow' everywhere. I don't know about newer versions of Clang, but I recall Chandler Carruth mentioning that LLV…

Java JITs are considerably more advanced than this. It's expensive to put in all the additional control flow edges to model exceptions, but once done, control and data flow analyses just work, as well as loop optimizations, code motion, inlining, register allocation--all of it "just works" (TM). Then you have to spit out a metric crapton of metadata to allow searching for the correct handler at runtime, but that's th…

Regarding putting in all the additional control flow edges: more edges mean fewer optimizations. That's not zero cost.

Re: C++ Exceptions: Under the Hood (2013)

#29
post #24

Earlier quoted context omitted.

Java JITs are considerably more advanced than this. It's expensive to put in all the additional control flow edges to model exceptions, but once done, control and data flow analyses just work, as well as loop optimizations, code motion, inlining, register allocation--all of it "just works" (TM). Then you have to spit out a metric crapton of metadata to allow searching for the correct handler at runtime, but that's th…

Java has a far, far more restricted view of exceptions than C++ and D have,[1] and hence more opportunities for optimization. I did implement exceptions in the Javascript compiler I implemented 20 years ago, and they're a cakewalk compared to C++. I also implemented a native Java compiler, including EH. As for clang, see what Chandler said. But maybe things have changed in the last couple years. [1] for example, Java…

I don't know the internals of clang very well, but everything I have heard second hand (and third hand) makes me think that its approach to modeling exceptions isn't very good.

Re: C++ Exceptions: Under the Hood (2013)

#30
post #26

Working with and implementing C++ exceptions for 30 years now, including implementing exception handling for Windows, DOS extenders, and Posix (all very different), and then re-implementing them for D, I have sadly come to the conclusion that exceptions are a giant mistake. 1. they are very hard to understand all the way down 2. they are largely undocumented in how they're implemented 3. they are slow when thrown 4.…

Can you describe your ideal error handling mechanisms? Or at least other mechanisms that feel more correct?

I'm not going to recommend any technique I don't personally have years of experience with. Too many times a paper that makes something look great tends to have fatal flaws that only emerge years later. Sort of like WW1 strategies that sounded good but in practice produced only mud and dead bodies.

As I mentioned in another comment, I've had good success in the trenches with the poisoning technique.

Post reply on HN