Boost logo

Boost Users :

Subject: Re: [Boost-users] [fiber] Fiber context switching during stack unwinding...
From: Oliver Seiler (oseiler_at_[hidden])
Date: 2018-02-28 20:27:51


I had seen that line in the docs (though an explanation of why would be
nice), but it really doesn't address the larger point that if you're
writing good exception-safe code, then you *aren't* in a catch block most
of the time. If I'm in a destructor, in particular, I can be there because
the stack is being unwound and there is an active exception. If I then go
and call, directly or indirectly, something that does a stack switch, then
I'm in this (seemingly) undefined behaviour.

Maybe you want to use ScopeExit in a fiber:

void foo(channel<int>& c) {
  BOOST_SCOPE_EXIT_ALL(&c) { c.push(0); };
  <other stuff that might throw>
}

Or maybe you are trying to compose a bunch of classes/functions that,
unbeknownst to you (e.g., via a virtual function) wind up stack switching
the current fiber, and these get called during stack unwinding. I don't see
a good way to deal with this, at the present time, short of simply
disabling exception entirely; what I find strange is that I see very little
in the way of discussion around how things like std::uncaught_exception()
or std::current_exception() do act and should act in conjunction with the
various proposals for lightweight thread support (resumable functions,
fibers, coroutines of various flavours, etc).

I didn't really want to make my original e-mail even longer than it was,
but beyond that one little warning in the Context documentation (but
seemingly not in the Fiber documentation), the only other place I've seen
mention of potential issues around this is in a pre-coroutine (resumable
functions) paper that only says "The await operator shall not be invoked in
a catch block of a try-statement", with a brief explanation in a footnote (
https://isocpp.org/files/papers/N4402.pdf); no mention restricting usage
during stack unwinding, though.

you could try to store the exeception in a std::exception_ptr ... leave the
> catch clause and then use the std::exception_ptr to transport the exception
> to another context (via jump)

Again, I'm not really talking about being in the catch clause, or that I'd
like to move the exception between contexts/fibers; I am concerned about
APIs that don't work as expected in contexts (e.g., in a catch block,
during stack unwinding with an active exception) that the calling code
might not even be aware they are in. Imagine a logging API built on fibers
written using one of the channel classes (e.g. log().push("my message"); ).
Whether that is realistic or not, restricting usage outside of catch
blocks, destructors, scope-guard APIs like ScopeExit, etc, seems pretty bad
to me if it results in weird exception behaviour (and crashes, in my
experience).

On Tue, Feb 27, 2018 at 10:56 PM, Oliver Kowalke via Boost-users <
boost-users_at_[hidden]> wrote:

>
> 2018-02-28 6:57 GMT+01:00 Stian Zeljko Vrba via Boost-users <
> boost-users_at_[hidden]>:
>
>> Hi,
>>
>>
>> The documentation for boost context contains the following warning: "Do
>> not jump from inside a catch block and then re-throw the exception in
>> another continuation. "
>>
>>
>> It's on this page: http://www.boost.org/doc/libs/1_66_0/libs/context/doc/
>> html/context/cc.html
>>
>
> +1
>
>
>> ------------------------------
>> *From:* Boost-users <boost-users-bounces_at_[hidden]> on behalf of
>> Oliver Seiler via Boost-users <boost-users_at_[hidden]>
>> *Sent:* Wednesday, February 28, 2018 6:45:16 AM
>> *To:* boost-users_at_[hidden]
>> *Cc:* Oliver Seiler
>> *Subject:* [Boost-users] [fiber] Fiber context switching during stack
>> unwinding...
>>
>> (Hopefully I'm not writing an essay for something that is a
>> gcc/libstdc++/Linux bug)
>>
>> I've been using Boost.Context for a number of years now, to do something
>> similar to what Boost.Fiber does. We recently upgraded our development
>> target environment to Debian 9 (gcc 6.3), and moved up to Boost 1.62.0, so
>> I've been looking at Boost.Fiber to replace how we're using Boost.Context
>> (because it looks like it could greatly simplify our code, among other
>> things).
>> One thing I ran into with Boost.Context was that it interacted in some
>> interesting ways with exception handling, and I haven't really seen any
>> discussion about it. Specifically, switching contexts with an active
>> exception (so during stack unwinding, or in a catch block) would result in
>> weird behaviour in the other context (std::uncaught_exception() returning
>> true, std::current_exception() returning the exception from the other
>> context, try/catches in the new context causing new problems when switching
>> back to the original context which is in the middle of stack unwinding,
>> etc).
>>
>> I chalked that up to limitations of the context switching, though I
>> haven't seen any mention of avoiding context switches with active
>> exceptions; presumably this is some interaction with gcc's exception
>> implementation, and would maybe need support from libunwind to save/restore
>> the exception state (I don't recall if I checked if clang produced similar
>> results, though I'll probably give it a go when I have the chance). So I
>> wasn't surprised when I ran into similar problems with Boost.Fiber.
>>
>> I am wondering why this aspect of usage isn't discussed in any of the
>> documentation; it would be nice if these libraries could work well with
>> language features like exceptions, but I understand that the language spec
>> doesn't really speak to the stack switching happening under-the-hood. It
>> actually wouldn't surprise me that this wasn't even a problem in all
>> environments, and just happens to be an artifact of the Linux
>> implementation, but then we're either talking about unspecified or
>> undefined behaviour, but would be nice to know. Even in the documents going
>> through the C++ standards committee I don't see much mention of how things
>> like coroutines should interact with something like
>> std::current_exception() (perhaps because it is assumed to "just work" and
>> doesn't need additional comment?)
>>
>> Anyone else ever run into issues related to this? Seems like any use of
>> RAII for exception handling would easily run into problems. Mostly I've
>> just found ways to work around it (e.g., not allowing the context switch if
>> std::uncaught_exception() or std::current_exception() indicate it would be
>> unsafe to do so, typically by throwing another exception) but this tends to
>> make libraries harder to use correctly (e.g., can't really allow context
>> switching in a destructor, or in a function called from a destructor, etc).
>>
>> Cheers
>> Oliver
>>
>
> you could try to store the exeception in a std::exception_ptr ... leave
> the catch clause and then use the std::exception_ptr to transport the
> exception to another context (via jump)
>
> _______________________________________________
> Boost-users mailing list
> Boost-users_at_[hidden]
> https://lists.boost.org/mailman/listinfo.cgi/boost-users
>
>



Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net