C++ Logo

std-proposals

Advanced search

Re: Stacktrace from exception

From: Edward Catmur <ecatmur_at_[hidden]>
Date: Thu, 29 Apr 2021 09:55:23 +0100
On Wed, 28 Apr 2021 at 22:54, Andrey Semashev via Std-Proposals <
std-proposals_at_[hidden]> wrote:

> On 4/28/21 11:51 PM, Edward Catmur via Std-Proposals wrote:
> > Absolutely. But bugs occur, and we call third-party library code that
> > may also have bugs.
>
> In case of a bug let it crash and collect the stacktraces then
> (possibly, with a core dump). If the bug leads to an exception - debug
> it once (with a debugger, logging, stacktraces - whatever means
> necessary), write a test, and then forget it. You will never see that
> exception again, and you will never need stacktraces automatically
> attached to exceptions.
>

Crashing is not the desired behavior. If it is possible to shut down
cleanly (flushing logs, raising incidents, releasing resources) then it is
better to do so.

But normally, an exception is not a bug but rather an exceptional
> situation. As opposed to a bug, an exception is the intended reaction to
> some input. Here, a stacktrace usually is not that interesting.
>

An exception is never the intended reaction to input, because if an input
is expected it should be handled through normal control flow.

> Quite the opposite. What you're suggesting is a recipe for a system
> > vulnerable to DoS. Yes, you would log the error, and you would
> possibly
> > log multiple times before throttling. But you do want to dispatch
> > errors
> > efficiently to have some time for processing valid data or requests.
> >
> > Not a concern, to be honest. Once a bug has been identified, all data
> > processed by the program is suspect, so even if the choice taken is to
> > keep running (and not shutdown safely) you'll likely have to rerun
> anyway.
>
> Again, an exception is not a bug. If your system routinely receives
> invalid requests, you want to deal with them fast so that valid requests
> still get to be processed.
>

Exceptions result from a program arriving in an unexpected state; thus they
are a bug, as we consider it.

Even if you want to keep the program running (and I do understand there are
cases where this is appropriate), throwing an exception incurs the cost of
stack unwinding, locking and unlocking mutexes, calling destructors, and
(in particular) loading the eh tables from a cold section, which may be way
out in L1 or even require a page fault to load from disk. Is the overhead
of a maybe 80 byte allocation really noticeable next to that?

> I'm opposed to doing this *implicitly* and *by default*. On the
> > contrary, I would welcome the feature if it was defined as explicitly
> > requested by the user.
> >
> > Also fine - as long as all of std::current_exception_stacktrace()
> > std::current_exception(), and throw; constitute an explicit request.
>
> The stacktrace must have been collected by the time when these functions
> are called. So no, they don't count as a request.
>

The compiler can determine whether those could be called by the handler,
and suppress stacktrace if they are not.

> > Well, obviously you'd use both std::nested_exception and
> > > Boost.Exception, not to mention your own exception hierarchy
> > inheriting
> > > from both. And std::exception is polymorphic, as is
> > boost::exception, so
> > > almost all of the time (except with some really old libraries)
> > there's
> > > no problem using dynamic_cast.
> >
> > Most types that you'd want to attach won't be polymorphic.
> >
> > Sure, so you dump them into your holds-anything exception object that is
> > mixed with std::nested_exception.
>
> Again, why would you mess with std::nested_exception?
>

When you are at a point to attach data to an exception, you already have an
exception_ptr from the original throw site.

> > The point of std::nested_exception is more that it allows you to
> > attach
> > > your own exception hierarchy to an existing exception of
> > arbitrary type.
> >
> > And why would you do that? I mean, unless you do literally have
> > multiple
> > exceptions that you want to chain together, why would you want to
> wrap
> > your data, like std::stacktrace for example, into another exception
> > type, just to use it with std::nested_exception? Which is not
> designed
> > to work as a container of arbitrary data in the first place to boot?
> >
> > No, there's no need to pull an owl on a globe since boost::exception
> > can
> > already be a base class for an exception, and provides the necessary
> > infrastructure for adding and extracting the attached data.
> >
> > Every library has its own exception hierarchy; hopefully they're
> > polymorphic and with luck they are based on std::exception or
> > boost::exception. But if they aren't, you have to deal with them anyway.
>
> I think, you missed my point. You don't attach exceptions, you attach
> arbitrary data that is not an exception to an exception. Furthermore,
> you may attach the same kind of data to different types of exceptions.
> And preferably you shouldn't be required to write an exception class for
> every such combination.
>

Yes, that's why you use a holds-anything exception class. But you also need
to mix in the original exception, wherever that was thrown from.

> Exceptions are never going to be efficient or elegant; whatever you can
> > get to work is good enough. As for attaching data, boost::exception is
> > nice enough, but it doesn't provide the necessary fine-grained access to
> > individual data items; all you can do is convert them to string
> > representation en bloc.
>
> Oh, no, you very much can access individual items, that's the point.
>
>
> https://www.boost.org/doc/libs/1_76_0/libs/exception/doc/get_error_info.html
>
> The ability to format all attached data along with the exception itself
> (
> https://www.boost.org/doc/libs/1_76_0/libs/exception/doc/diagnostic_information.html)
>
> is just a cherry on top.
>

That only works if you know the type of the item. There's no way to iterate
over items of unknown type individually.

Received on 2021-04-29 03:55:53