Boost logo

Boost :

Subject: Re: [boost] [Stacktrace] review
From: Niall Douglas (s_sourceforge_at_[hidden])
Date: 2016-12-16 14:05:26


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/

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk