C++ Logo

std-proposals

Advanced search

Re: Stacktrace from exception

From: Edward Catmur <ecatmur_at_[hidden]>
Date: Wed, 28 Apr 2021 21:51:38 +0100
On Wed, 28 Apr 2021 at 20:23, Andrey Semashev via Std-Proposals <
std-proposals_at_[hidden]> wrote:

> No. Optimal would be one allocation for the whole stacktrace, with no
> reallocations later. Yet more optimal would be one allocation for both
> the exception and the stacktrace, but that couples the exception and the
> stacktrace, so probably not feasible. But the most optimal is to not
> collect the stacktrace at all, unless explicitly requested by the user.
>

It could be determined by examining the catch block whether
std::current_exception_stacktrace could be called. But there's also
std::current_exception() to consider, and also throw;.

IMO, exceptions thrown by the standard library are close to useless. Not
> in least part for the poor QoI of the standard libraries in this regard,
> as many of them don't produce an informative error message with any
> relevant information. Also because the standard library cannot provide
> any context-specific details about the error (i.e. std::vector::at
> cannot know what the vector is and where the index comes from, only the
> caller knows that and can provide that information in the log). For this
> reason, you should normally code so that you check the necessary
> preconditions in your code before calling the standard library, and then
> call standard library methods that don't throw.
>

Absolutely. But bugs occur, and we call third-party library code that may
also have bugs.

Stacktraces attached to exceptions don't solve this problem, as they
> don't provide you information that is crucial to the problem
> investigation, namely the input and the state of the program when the
> error occurred.
>

Capturing and retaining that information is simply infeasible once there is
enough of it, and if you don't have the luxury of making a copy on entry.
(Although, now that you mention it, we have had some success with dumping
core at the throw site - but not everyone agrees.) A stacktrace is
invaluably rich in information compared to almost any other debugging aid,
since it tells you the path through the program to the point the error
became apparent.

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.

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.

> 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.

> 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.
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.

Received on 2021-04-28 15:51:52