Re: [boost] Re: [prereview request][fsm]

--- Rob Stewart <stewart@sig.com> wrote:
From: "E. Gladyshev" <eegg@comcast.net>
From: "Rob Stewart" <stewart@sig.com>
From: "E. Gladyshev" <eegg@comcast.net>
From: "Rob Stewart" <stewart@sig.com>
[...]
1. Some platforms pose non-C++ exceptions as normal C++ exception. You don't always want those platfrom specific exceptions trigger a whole bunch of stuff in your program.
The only platform I know of that does that is Windows/MSVC
It makes it pretty common, doesn't it. :)
you can handle structured exceptions specially. Perhaps it means that boost::fsm needs to provide a means to install an exception handler for those exceptions not already recognized by the library:
try { throw; } catch (...) { boost::fsm::detail::handle_exception(); }
void boost::fsm::detail::handle_exception() { try { throw; } catch (type1 const &) { ... }; catch (type2 const &) { ... }; catch (type3 const &) { ... }; catch (...) { user_handler(); } } where user_handler is a pointer to function that's initialized to std::unexpected() and can be overridden by the library user.
Adding user_handler() doesn't stop stack unwinding. I think you are missing the point. The issue is not in how to process SEH exceptions (or any other unhandled exception) the issue is in how not to trigger stack unwinding (for all exceptions) and still be able discriminate user exception types generically in FSM. Your solution doesn't solve this problem.
It may also be that SEH can be configured to intervene before a C++ exception is generated by the RTL so those never become C++ exceptions that can muck up the works.
It is not trivial... but it is out of the FSM topic.
2. Your design assumes that all possible exceptions are known and you handle them. So any unhandled exception is a bug.
Not quite. What I was showing would rethrow any unknown exception, leaving to clients to determine how to handle it.
It is not safe to trigger stack unwinding in a buggy environment.
If you say so. Every application and platform with which I work is buggy and yet I manage to use exceptions and stack unwinding works.
What do you mean by "stack unwinding works". Do you mean that even if the exception is caused by a bug, stack unwinding didn't make things worse or less safer? Well, it's a long shot... [...]
This is just another case of things not being as pretty as one might like but that doesn't mean stack unwinding is faulty.
Sorry, who said that stack unwinding is faulty? Eugene

eegg@comcast.net writes:
1. Some platforms pose non-C++ exceptions as normal C++ exception. You don't always want those platfrom specific exceptions trigger a whole bunch of stuff in your program.
The only platform I know of that does that is Windows/MSVC
It makes it pretty common, doesn't it. :)
And there are other such platforms. The details escape me at the moment. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

----- Original Message ----- From: "David Abrahams" <dave@boost-consulting.com>
eegg@comcast.net writes:
1. Some platforms pose non-C++ exceptions as normal C++ exception. You don't always want those platfrom specific exceptions trigger a whole bunch of stuff in your program.
The only platform I know of that does that is Windows/MSVC
It makes it pretty common, doesn't it. :)
And there are other such platforms. The details escape me at the moment.
The details escape me too but I've heard something SEH related in HP Tru64 UNIX. Eugene

From: eegg@comcast.net
--- Rob Stewart <stewart@sig.com> wrote:
From: "E. Gladyshev" <eegg@comcast.net>
From: "Rob Stewart" <stewart@sig.com>
From: "E. Gladyshev" <eegg@comcast.net>
From: "Rob Stewart" <stewart@sig.com>
1. Some platforms pose non-C++ exceptions as normal C++ exception. You don't always want those platfrom specific exceptions trigger a whole bunch of stuff in your program.
The only platform I know of that does that is Windows/MSVC
It makes it pretty common, doesn't it. :)
Sad, but true. (Well, the Windows part, I mean. MSVC 7.1 is quite good, I understand.)
you can handle structured exceptions specially. Perhaps it means that boost::fsm needs to provide a means to install an exception handler for those exceptions not already recognized by the library:
try { throw; } catch (...) { boost::fsm::detail::handle_exception(); }
void boost::fsm::detail::handle_exception() { try { throw; } catch (type1 const &) { ... }; catch (type2 const &) { ... }; catch (type3 const &) { ... }; catch (...) { user_handler(); } } where user_handler is a pointer to function that's initialized to std::unexpected() and can be overridden by the library user.
Adding user_handler() doesn't stop stack unwinding. I think you are missing the point. The issue is not in how to process SEH exceptions (or any other unhandled exception) the issue is in how not to trigger stack unwinding (for all exceptions) and still be able discriminate user exception types generically in FSM. Your solution doesn't solve this problem.
You stated that, but no one had proffered a good reason for wanting to avoid stack unwinding by the time I wrote that. You mentioned non-C++ exceptions infiltrating via catch (...), so I was discussing techniques whereby a concerned library user might be able to keep SEH from interfering with the proposed EH in boost::fsm.
It may also be that SEH can be configured to intervene before a C++ exception is generated by the RTL so those never become C++ exceptions that can muck up the works.
It is not trivial... but it is out of the FSM topic.
The point is that the library client that is bothered by boost::fsm triggering stack unwinding probably has a means of dealing with the exceptions that would otherwise undesirably cause stack unwinding.
2. Your design assumes that all possible exceptions are known and you handle them. So any unhandled exception is a bug.
Not quite. What I was showing would rethrow any unknown exception, leaving to clients to determine how to handle it.
It is not safe to trigger stack unwinding in a buggy environment.
If you say so. Every application and platform with which I work is buggy and yet I manage to use exceptions and stack unwinding works.
What do you mean by "stack unwinding works". Do you mean that even if the exception is caused by a bug, stack unwinding didn't make things worse or less safer? Well, it's a long shot...
[...]
This is just another case of things not being as pretty as one might like but that doesn't mean stack unwinding is faulty.
Sorry, who said that stack unwinding is faulty?
You said "it is not safe to trigger stack unwinding in a buggy environment." I'm saying that despite bugs in compilers and applications, one can still take advantage of stack unwinding. Sure, things can -- and do -- go wrong and you sometimes track those back to compiler bugs. Nevertheless, you use the facilities you have. What I understand you to say is that there is some error indicated by SEH that will be caught by catch (...) and that will trigger stack unwinding and it is unwise to permit stack unwinding at that point. Is that really any different than stack unwinding because of an out of range index or insufficient memory? -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

----- Original Message ----- From: "Rob Stewart" <stewart@sig.com> [...]
The point is that the library client that is bothered by boost::fsm triggering stack unwinding probably has a means of dealing with the exceptions that would otherwise undesirably cause stack unwinding.
In real life, it is a very tough requirement to meet... and it'll make you code not portable. The bottom line is that catch(...) doesn't allow you to make the following important design decision: - All exceptions have to be derived from E. - All other exceptions are caused by a bug and should not trigger stack unwinding. [...]
Sorry, who said that stack unwinding is faulty?
You said "it is not safe to trigger stack unwinding in a buggy environment."
It is not the same as "stack unwinding is faulty", is it? [...]
What I understand you to say is that there is some error indicated by SEH that will be caught by catch (...) and that will trigger stack unwinding and it is unwise to permit stack unwinding at that point. Is that really any different than stack unwinding because of an out of range index or insufficient memory?
Yes, it is very different! The "out of range" or "insufficient memory exceptions" don't happen on their own. You have to throw them *explicitly. So before throwing them, you can make sure that the broken invariant (if any) is restored . If the invariant is restored, stack unwinding is safe. SEH's on the other hand can happen at "any place" in your program (even when the invariant is broken). If the invariant is broken, stack unwinding is not safe. Anyway, I think that this issue isn't directly related to fsm. There was an extensive discussion about this stuff at c++.moderated. You might want to take a look at it. Eugene

From: "E. Gladyshev" <eegg@comcast.net>
From: "Rob Stewart" <stewart@sig.com>
The point is that the library client that is bothered by boost::fsm triggering stack unwinding probably has a means of dealing with the exceptions that would otherwise undesirably cause stack unwinding.
In real life, it is a very tough requirement to meet... and it'll make you code not portable.
The preprocessor can handle that for those platforms where you have to worry about SEH, right?
The bottom line is that catch(...) doesn't allow you to make the following important design decision: - All exceptions have to be derived from E. - All other exceptions are caused by a bug and should not trigger stack unwinding.
Based upon Dave A mentioning that unhandled exceptions might lead to a core dump, I can see that no stack unwinding could be useful. The alternative is to rerun the application under a debugger, attempt to recreate the conditions leading up to the exception, and then inspect the call stack just as the exception is about to be thrown (depending upon the capabilities of your debugger, of course).
Sorry, who said that stack unwinding is faulty?
You said "it is not safe to trigger stack unwinding in a buggy environment."
It is not the same as "stack unwinding is faulty", is it?
I guess I meant using it was a faulty enterprise. The point was that you were saying if things are buggy, don't make use of stack unwinding. I think I now see that you meant permitting exceptions to propagate unhandled prevents stack unwinding and leads to a core dump which makes tracking down the bug easier.
What I understand you to say is that there is some error indicated by SEH that will be caught by catch (...) and that will trigger stack unwinding and it is unwise to permit stack unwinding at that point. Is that really any different than stack unwinding because of an out of range index or insufficient memory?
Yes, it is very different! The "out of range" or "insufficient memory exceptions" don't happen on their own. You have to throw them
Sure they do: if you call new, you get std::bad_alloc. It is the RTL that throws the exception. Granted, the exception occurs at a well defined time and the same can't be said for structured exceptions, right?
*explicitly. So before throwing them, you can make sure that the broken invariant (if any) is restored . If the invariant is restored, stack unwinding is safe.
What about exceptions thrown to indicate a violated invariant? That is, the basic guarrantee? IOW, if an invariant is violated, the object can be left in a destructible state, but nothing more can be said for its use.
SEH's on the other hand can happen at "any place" in your program (even when the invariant is broken). If the invariant is broken, stack unwinding is not safe.
Then you can't write code with the basic guarrantee can you?
Anyway, I think that this issue isn't directly related to fsm. There was an extensive discussion about this stuff at c++.moderated. You might want to take a look at it.
I'll try to do that. Thanks. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

Rob Stewart wrote:
From: "E. Gladyshev" <eegg@comcast.net>
From: "Rob Stewart" <stewart@sig.com>
What I understand you to say is that there is some error indicated by SEH that will be caught by catch (...) and that will trigger stack unwinding and it is unwise to permit stack unwinding at that point. Is that really any different than stack unwinding because of an out of range index or insufficient memory?
Yes, it is very different! The "out of range" or "insufficient memory exceptions" don't happen on their own. You have to throw them
Sure they do: if you call new, you get std::bad_alloc. It is the RTL that throws the exception. Granted, the exception occurs at a well defined time and the same can't be said for structured exceptions, right?
*explicitly. So before throwing them, you can make sure that the broken invariant (if any) is restored . If the invariant is restored, stack unwinding is safe.
What about exceptions thrown to indicate a violated invariant?
Throwing exceptions to indicate a violated invariant is a pretty bad idea; it means you've left part of your system with broken invariants; i.e. you can't depend on that part of the system for anything.
That is, the basic guarrantee?
The basic guarantee means no invariants are violated.
IOW, if an invariant is violated, the object can be left in a destructible state, but nothing more can be said for its use.
If part of the invariants of an object are that it may be placed into a destructible state, but nothing else works, then its invariants really aren't violated, aren't they?
SEH's on the other hand can happen at "any place" in your program (even when the invariant is broken). If the invariant is broken, stack unwinding is not safe.
Then you can't write code with the basic guarrantee can you?
Not with asynchronous SEH's flying around. SEH's are a problem, aren't they? Bob

----- Original Message ----- From: "Robert Bell" <belvis@imageworks.com>
Rob Stewart wrote:
From: "E. Gladyshev" <eegg@comcast.net>
SEH's on the other hand can happen at "any place" in your program (even when the invariant is broken). If the invariant is broken, stack unwinding is not safe.
Then you can't write code with the basic guarrantee can you?
Not with asynchronous SEH's flying around. SEH's are a problem, aren't
[...] they?
Yeah, it is a nasty thing... Actually in real life, those poorly documented third party libraries that throw something that you don't expect them to is a problem too. I think that in practice you always have to be very careful about catching everything that is thrown at you. :) Eugene

Rob Stewart <stewart@sig.com> writes:
*explicitly. So before throwing them, you can make sure that the broken invariant (if any) is restored . If the invariant is restored, stack unwinding is safe.
What about exceptions thrown to indicate a violated invariant?
Don't do that. Assert instead.
That is, the basic guarrantee?
Huh? That has little or no relation to "exceptions thrown to indicate a violated invariant".
IOW, if an invariant is violated, the object can be left in a destructible state
Not in general. If an invariant is violated, you can't count on anything, including destructibility. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com
participants (5)
-
David Abrahams
-
E. Gladyshev
-
eegg@comcast.net
-
Rob Stewart
-
Robert Bell