Re: [boost] Exception Visitor

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Alexander Nasonov Sent: Friday, July 28, 2006 12:54 PM Subject: Re: [boost] Exception Visitor
Please, NO! It's my experience that one catch(...) in a program may be a source of many annoying glitches that users report periodically but developers don't understand what's going on. Removing this often helps. Users start reporting crashes. Most difficult at this stage is to find a user who is able to run Dr. Watson, check 'Create Crash Dump File' and send a dump to developers :)
Also worth noting that SEH is not standard C/C++.
FWIW, I'd like to strongly second that. When catching SEH exceptions (like catch(...) does), predictable behaviour is only possible if you compile for 'asynchronous exception handling', which according to the docs increases the generated code size (I don't know about the runtime performance cost). If you compile for 'synchronous exception handling' (the more usual thing, I believe), you should either be prepared to live with bad cleanup of the stack or you install a global SEH-exception handler in each thread you start, which does nothing but rethrow and therefore crash the app. IMHO, that's nothing a library should impose on its apps. Anyway, I fail to see what's the benefit of catching segfaults _as the default behaviour_ (that's not to say there aren't applications that need to do). FWIW again, I won't use a solution which includes catch(...) anytime soon (and esp. not if it's done in a pervasive manner). cheers, aa -- Andreas Ames | Programmer | Comergo GmbH | Voice: +49 69 7505 3213 | ames AT avaya DOT com

On 7/28/06, Ames Andreas <Andreas.Ames@comergo.com> wrote:
FWIW, I'd like to strongly second that. When catching SEH exceptions (like catch(...) does), predictable behaviour is only possible if you compile for 'asynchronous exception handling', which according to the docs increases the generated code size (I don't know about the runtime performance cost). If you compile for 'synchronous exception handling' (the more usual thing, I believe), you should either be prepared to live with bad cleanup of the stack or you install a global SEH-exception handler in each thread you start, which does nothing but rethrow and therefore crash the app. IMHO, that's nothing a library should impose on its apps. Anyway, I fail to see what's the benefit of catching segfaults _as the default behaviour_ (that's not to say there aren't applications that need to do).
Ah, I think that I have been misunderstood. I simply said that I thought that catching SEH exceptions _could_ be a good thing that and that I would _like_ for all exceptions to be caught. I don't have any particular interest (or, more importantly, time) in implementing something like that and foisting it upon people. I'm reasonably happy with BOOST_CATCH as it exists right now, so I'm going to explore ways to make it easier for users or more efficient. I am not going to force users into some sort of exception handling choice that they don't want. Keep the comments comin'. Jeremy

Hello Jeremy! There is a strong opinion against catch(...) clause. But problems, mentioned by Alexander Nasonov and Ames Andreas could be worked around. 1) define a BOOST_BROKEN_CATCH_ALL configuration macro that is non-zero when compiling in mode where catch(...) is dangerous (BOOST_MSVC is defined and _MSC_VER is in a predefined range. according to Peter Dimov MSVC 8 doesn't catch SEH exceptions with ... by default) 2) protect all code in your catcher.hpp with this macro and place #error message in #else branch that describes the problem with catch(...) on a given platform. Later it can be replaced with macroses, proposed by Alexander Nasonov: try { throw std::logic_error("testing"); } BOOST_CATCH_PP_SEQ((ex1)(ex2)(ex3), my_exception_handler()); alternatively or additionally, you can provide here an implementation that catches not for ... but for std::exception& It completely eliminates the original problem but restricts user to only std::exception - derived exceptions. to extend this approach a bit you can provide user a possibility to define BOOST_EXCEPTION_BASE_1, BOOST_EXCEPTION_BASE_2, etc up to predefined limit. and use these macros to catch (BOOST_EXCEPTION_BASE_N) for all N defined by user. Alexander? Ames? What do you prefer here? 3) write a test case for the macro defined in (1). it should contain code that generates SEH and tries to catch it with catch(...). if it succeed - test fails, else - passes. finally, protect this code with the macro defined in (1), so if the macro defined correctly, test code expands to nothing on problematic platforms, else expands to all test code. But I'm not sure if and how it can be implemented on all platforms, though. As a first step you can provide a very simple definition for BOOST_BROKEN_CATCH_ALL macros and protect your catcher code with it (+ #error message) and let interested people do the rest ;-) Best, Oleg Abrosimov. PS: what about BOOST_DEFINE_EXCEPTION_HANDLER stuff? do you need a help with it? Jeremy Day wrote:
On 7/28/06, Ames Andreas <Andreas.Ames@comergo.com> wrote:
FWIW, I'd like to strongly second that. When catching SEH exceptions (like catch(...) does), predictable behaviour is only possible if you compile for 'asynchronous exception handling', which according to the docs increases the generated code size (I don't know about the runtime performance cost). If you compile for 'synchronous exception handling' (the more usual thing, I believe), you should either be prepared to live with bad cleanup of the stack or you install a global SEH-exception handler in each thread you start, which does nothing but rethrow and therefore crash the app. IMHO, that's nothing a library should impose on its apps. Anyway, I fail to see what's the benefit of catching segfaults _as the default behaviour_ (that's not to say there aren't applications that need to do).
Ah, I think that I have been misunderstood. I simply said that I thought that catching SEH exceptions _could_ be a good thing that and that I would _like_ for all exceptions to be caught. I don't have any particular interest (or, more importantly, time) in implementing something like that and foisting it upon people. I'm reasonably happy with BOOST_CATCH as it exists right now, so I'm going to explore ways to make it easier for users or more efficient. I am not going to force users into some sort of exception handling choice that they don't want.
Keep the comments comin'.
Jeremy _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Oleg Abrosimov wrote:
Hello Jeremy!
There is a strong opinion against catch(...) clause. But problems, mentioned by Alexander Nasonov and Ames Andreas could be worked around.
1) define a BOOST_BROKEN_CATCH_ALL configuration macro that is non-zero when compiling in mode where catch(...) is dangerous (BOOST_MSVC is defined and _MSC_VER is in a predefined range. according to Peter Dimov MSVC 8 doesn't catch SEH exceptions with ... by default) 2) protect all code in your catcher.hpp with this macro and place #error message in #else branch that describes the problem with catch(...) on a given platform. Later it can be replaced with macroses, proposed by Alexander Nasonov: try { throw std::logic_error("testing"); } BOOST_CATCH_PP_SEQ((ex1)(ex2)(ex3), my_exception_handler());
Does proposed workaround have uniform behavior on all platforms?
alternatively or additionally, you can provide here an implementation that catches not for ... but for std::exception& It completely eliminates the original problem but restricts user to only std::exception - derived exceptions.
to extend this approach a bit you can provide user a possibility to define BOOST_EXCEPTION_BASE_1, BOOST_EXCEPTION_BASE_2, etc up to predefined limit. and use these macros to catch (BOOST_EXCEPTION_BASE_N) for all N defined by user.
Alexander? Ames? What do you prefer here?
When I jumped in into this discussion, I didn't intend to produce new boost library as I didn't like use of rethrow. I believe that exception handling should be very simple and not require a lot of metaprogramming like sorting handlers, creating MPL sequence of handled exception on the fly and so on. So, this library should a simple utility library that doesn't rethow if possible and doesn't hide a lot from a user. 1. Catch a list of exceptions in one line: try { throw std::logic_error("testing"); } BOOST_CATCH_PP_SEQ((ex1)(ex2)(ex3), my_exception_handler()); There is no need for MPL counterpart because you can always transform PP sequence into MPL sequence (but this functionaly seems to be missing in boost). If you can't do that (e.g. you need to mpl::push_back, or apply mpl::transform_view), then this library goes beyond a simple utility ;-) 2. Catch and dispatch (or visit, if you like) try { throw std::logic_error("testing"); } BOOST_CATCH_AND_DISPATCH(std::exception&, my_exception_handler()); This code rethows but it doesn't catch(...) but rather catch(std::exception&). Needless to say that my_exception_handler should be as simple as possible. Macros inside this class should be avoided because it's often impossible to go to a definition of a function inside it. Currently, my_exception_handler in item 1 has different (and much simpler) interface compared to that from item 2. It would be nice to have common interface. -- Alexander Nasonov Project Manager at Akmosoft ( http://www.akmosoft.com ) Blog: http://nasonov.blogspot.com Email: $(FirstName) dot $(LastName) at gmail dot com

Gentlemen, I just want to start by saying thanks for the comments. I'm wrapping my brain around some of it, and hopefully I'll have time to work on this again very soon. On 8/8/06, Alexander Nasonov <alnsn@yandex.ru> wrote:
So, this library should a simple utility library that doesn't rethow if possible and doesn't hide a lot from a user.
I will do some research into using preprocessor metaprogramming to remove the rethrow, or at least provide a macro that does that. 1. Catch a list of exceptions in one line:
try { throw std::logic_error("testing"); } BOOST_CATCH_PP_SEQ((ex1)(ex2)(ex3), my_exception_handler());
There is no need for MPL counterpart because you can always transform PP sequence into MPL sequence (but this functionaly seems to be missing in boost). If you can't do that (e.g. you need to mpl::push_back, or apply mpl::transform_view), then this library goes beyond a simple utility ;-)
2. Catch and dispatch (or visit, if you like)
try { throw std::logic_error("testing"); } BOOST_CATCH_AND_DISPATCH(std::exception&, my_exception_handler());
This code rethows but it doesn't catch(...) but rather catch(std::exception&).
Needless to say that my_exception_handler should be as simple as possible. Macros inside this class should be avoided because it's often impossible to go to a definition of a function inside it.
Currently, my_exception_handler in item 1 has different (and much simpler) interface compared to that from item 2. It would be nice to have common interface.
I personally think that item 2 has the easier interface. I will definitely work on a macro where you can specify what to catch, in lieu of always catching ... . Furthermore, I really like using the MPL sequence, because I found that it is very easy to order the exceptions so that you don't accidentally have catch(std::exception&) before you catch a derived exception, such as std::logic_error. Jeremy

Ames Andreas wrote:
FWIW, I'd like to strongly second that. When catching SEH exceptions (like catch(...) does), predictable behaviour is only possible if you compile for 'asynchronous exception handling',
FWIW, MSVC 8 doesn't catch SEH exceptions with ... by default.

I've searched boost sources for catch(...) and catch (...) clauses and found many "interesting" examples like that (libs/regex/src/fileiter.cpp): file_iterator::file_iterator() { _root = _path = 0; ref = 0; #ifndef BOOST_NO_EXCEPTIONS try{ #endif _root = new char[MAX_PATH]; BOOST_REGEX_NOEH_ASSERT(_root) _path = new char[MAX_PATH]; BOOST_REGEX_NOEH_ASSERT(_path) ptr = _path; *_path = 0; *_root = 0; ref = new file_iterator_ref(); BOOST_REGEX_NOEH_ASSERT(ref) ref->hf = _fi_invalid_handle; ref->count = 1; #ifndef BOOST_NO_EXCEPTIONS } catch(...) { delete[] _root; delete[] _path; delete ref; throw; } #endif } Note that catch(...) is used only to free resources and this code can be trivially converted to equally good one but without catch(...) clause using std::vector for _root and _path and std::auto_ptr for ref there are many places in boost sourcebase like the above. It seems that you and Alexander Nasonov have a need to check boost libraries that you use for such quasi-bugs ;-) May be there should be a boost-wide macro like BOOST_BROKEN_CATCH_ALL and some policy to use it through all the codebase? Best, Oleg Abrosimov. Ames Andreas wrote:
-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Alexander Nasonov Sent: Friday, July 28, 2006 12:54 PM Subject: Re: [boost] Exception Visitor
Please, NO! It's my experience that one catch(...) in a program may be a source of many annoying glitches that users report periodically but developers don't understand what's going on. Removing this often helps. Users start reporting crashes. Most difficult at this stage is to find a user who is able to run Dr. Watson, check 'Create Crash Dump File' and send a dump to developers :)
Also worth noting that SEH is not standard C/C++.
FWIW, I'd like to strongly second that. When catching SEH exceptions (like catch(...) does), predictable behaviour is only possible if you compile for 'asynchronous exception handling', which according to the docs increases the generated code size (I don't know about the runtime performance cost). If you compile for 'synchronous exception handling' (the more usual thing, I believe), you should either be prepared to live with bad cleanup of the stack or you install a global SEH-exception handler in each thread you start, which does nothing but rethrow and therefore crash the app. IMHO, that's nothing a library should impose on its apps. Anyway, I fail to see what's the benefit of catching segfaults _as the default behaviour_ (that's not to say there aren't applications that need to do).
FWIW again, I won't use a solution which includes catch(...) anytime soon (and esp. not if it's done in a pervasive manner).
cheers,
aa
participants (5)
-
Alexander Nasonov
-
Ames Andreas
-
Jeremy Day
-
Oleg Abrosimov
-
Peter Dimov