Date: Thu, 12 Nov 2020 22:22:54 +0300
чт, 12 нояб. 2020 г. в 19:03, Andrey Semashev via Std-Proposals
<std-proposals_at_[hidden]>:
> I'm not sure I understand how that would work. Saving a frame pointer is
> not enough since stack frames would be naturally destroyed during
> unwinding, so at the point where you catch the exception and about to
> get the stacktrace the pointer is useless.
We're saving not the frame, but the frame pinter - a return address to
the caller. That address is a pointer to the code, to the actual
instructions. When the frame is destroyed the pointer to the
instructions is still valid (there are nuances with DSO unloading,
let's leave those out of scope). Later, that pointer could be used to
get the human readable name of the caller.
> Generating stacktraces at compile time also doesn't seem feasible, since
> there may be a lot ways the control could get to a particular throw
> statement. So it seems some state capturing should happen at run time,
> and that work could have a linear complexity.
When you call std::stacktrace::current() it iterates through the
linked list of frames, storing return addresses. Operation takes
linear time from the frames count.
When stack unwinding is triggered by the exception, it does pretty the
same things: goes through the frames and calls destructors for
constructed objects. The operation takes linear time from count of
objects to destroy and count of frames.
You can embed the functionality of std::stacktrace::current() into the
stack unwinding to iterate only once through a list of frames. That's
a micro optimization, stack unwinding does an insane amount of
additional work (like locking mutex multiple times).
With -fomit-frame-pointer the things become hairy, but the pointer to
caller is still easily reachable from the stack unwinding.
> >> This really needs to be opt-in, but in that case you can just get the
> >> stacktrace in your exception's constructor?
> >
> > You can use std::stracktrace in your exceptions with C++23. However,
> > getting stacktraces for any exception out-of-the-box is a tempting
> > feature, especially for big codebases with legacy parts.
>
> Legacy code bases won't be using new features, like std::stracktrace.
Yes, but modern codebases may use legacy code. Legacy code could throw
an exception, modern runtime will embed a trace into it and stacktrace
from legacy code could be used in modern codebase. In theory.
> I would rather prefer to have a standard way to attach arbitrary
> information to exceptions, like Boost.Exception.
Hm... that's doable in the same non-ABI-breaking way on Itanium. No
idea about other platforms.
<std-proposals_at_[hidden]>:
> I'm not sure I understand how that would work. Saving a frame pointer is
> not enough since stack frames would be naturally destroyed during
> unwinding, so at the point where you catch the exception and about to
> get the stacktrace the pointer is useless.
We're saving not the frame, but the frame pinter - a return address to
the caller. That address is a pointer to the code, to the actual
instructions. When the frame is destroyed the pointer to the
instructions is still valid (there are nuances with DSO unloading,
let's leave those out of scope). Later, that pointer could be used to
get the human readable name of the caller.
> Generating stacktraces at compile time also doesn't seem feasible, since
> there may be a lot ways the control could get to a particular throw
> statement. So it seems some state capturing should happen at run time,
> and that work could have a linear complexity.
When you call std::stacktrace::current() it iterates through the
linked list of frames, storing return addresses. Operation takes
linear time from the frames count.
When stack unwinding is triggered by the exception, it does pretty the
same things: goes through the frames and calls destructors for
constructed objects. The operation takes linear time from count of
objects to destroy and count of frames.
You can embed the functionality of std::stacktrace::current() into the
stack unwinding to iterate only once through a list of frames. That's
a micro optimization, stack unwinding does an insane amount of
additional work (like locking mutex multiple times).
With -fomit-frame-pointer the things become hairy, but the pointer to
caller is still easily reachable from the stack unwinding.
> >> This really needs to be opt-in, but in that case you can just get the
> >> stacktrace in your exception's constructor?
> >
> > You can use std::stracktrace in your exceptions with C++23. However,
> > getting stacktraces for any exception out-of-the-box is a tempting
> > feature, especially for big codebases with legacy parts.
>
> Legacy code bases won't be using new features, like std::stracktrace.
Yes, but modern codebases may use legacy code. Legacy code could throw
an exception, modern runtime will embed a trace into it and stacktrace
from legacy code could be used in modern codebase. In theory.
> I would rather prefer to have a standard way to attach arbitrary
> information to exceptions, like Boost.Exception.
Hm... that's doable in the same non-ABI-breaking way on Itanium. No
idea about other platforms.
-- Best regards, Antony Polukhin
Received on 2020-11-12 13:23:09