On 16 Dec 2016 at 12:36, Gavin Lambert wrote:
On 15/12/2016 20:46, Niall Douglas wrote:
Also, I'm not sure about other compilers, but with MSVC thrown exceptions always carry a stack trace with them anyway; it's possible to extract the stack trace from any exception with some platform-dependent code (without any decoration on the throw -- and depending on build options, it can even work for null references and other CPU exceptions, although some misguided people dislike that).
I was not aware that this is the case except when /EHa is used. Indeed, I had thought one of the big optimisations of /EHs was precisely the fact that backtraces are *not* captured, thus making C++ exception throws vastly faster than Win32 structured exception throws and the point of using /EHs.
BTW I did some research and SEH exceptions do NOT capture stack backtraces. They do dump a CONTEXT structure, and from that you can walk a stack backtrace. This was the only legal way of getting a CONTEXT for the calling thread until Vista.
The following code *does* print "caught exception" (in both Debug and Release) even when compiled with /EHsc. Granted I suppose this doesn't explicitly prove that a stack trace was captured, but I think it proves that C++ exceptions are still internally implemented as SEH exceptions, and so GetExceptionInformation (among other things) can probably still be used to extract the stack context.
We have to be careful here. There is the SEH unwind mechanism and there is SEH itself. Absolutely everything unwinding a stack uses the former for any language, even Visual Basic, and hence C++ too. The latter is merely a client of the universal unwind mechanism, same as C++ exceptions is also implemented as a client of that mechanism. That's why throwing a C++ exception will get caught by a SEH exception handler, though without knowledge of the internal SEH codes MSVCRT uses you couldn't do much with that. Point is, it's universal and interoperable for all programming languages which can invert control flow (LLVM and GCC have a similar universal unwind framework). I also looked up some benchmarks. A C++ and SEH exception throw and catch costs about 2 microseconds on x86 on MSVC back in 2011 on a fairly low end CPU for the time. x86 SEH still uses the old setjmp/longjmp mechanism i.e. each stack frame pushes its unwind handler and pops it off the stack after i.e. it is not a "zero runtime cost" exceptions implementation. For x64, SEH unwind can now use table based unwinds i.e. zero runtime overhead exception, which SEH exposes as "vectored exception handling APIs". I didn't find any benchmarks online for what a throw and catch is on MSVC under x64, but it is likely to still be under 2 microseconds. I'm just about to go back onto minding newborn duty so I can't write the benchmark myself, but if anyone could quickly throw together a benchmark comparing C++ to SEH exception throw and catch on VS2015 it would be appreciated (just make sure the optimiser hasn't elided the code entirely). Just to remind everyone, a seven deep stack backtrace costs about 30 microseconds using the very optimised NT kernel backtrace routine. It is therefore a significant order of magnitude overhead addition to the cost of throwing and catching exceptions. Personally speaking, I would not make backtracing on exception throw default on therefore. Niall -- ned Productions Limited Consulting http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/