Boost logo

Boost :

Subject: Re: [boost] [Thread] Win32 exception handling
From: David Abrahams (dave_at_[hidden])
Date: 2008-11-26 12:19:58


on Wed Nov 26 2008, Matt Gruenke <mgruenke-AT-intellivid.com> wrote:

> vicente.botet wrote:
>> ----- Original Message -----
>> From: "Matt Gruenke"
>
>>> The catch (...) is one of the reasons we don't use boost::thread. I even filed a
>>> bug on it:
>>>
>>>
> http://sourceforge.net/tracker/index.php?func=detail&aid=1274707&group_id=7586&atid=357586>>
>> When I try to open this page anerror apears. Can you post the ticket?
>>
>
> That bug tracker is apparently obsolete. As I know of no way to gain access to my
> filing, here's the text:
>
> Feature Requests item #1274707, was opened at 2005-08-27 13:10
> You can respond by visiting:
> https://sourceforge.net/tracker/?func=detail&atid=357586&aid=1274707&group_id=7586
>
> Category: thread
> Group: None
> Status: Open
> Resolution: None
> Priority: 5
> Submitted By: Matthew Gruenke (mgruenke)
> Assigned to: William E. Kempf (bill_kempf)
> Summary: Remove try/catch(...) in thread.cpp:thread_proxy()
>
> Initial Comment:

> THE CASE AGAINST try {} catch (...) {} IN
> libs/thread/src/thread.cpp:thread_proxy()

That ticket has been reincarnated at http://svn.boost.org/, as #476,
which someone closed as fixed(!) and worse, there seems to be a bug in
Trac that prevents the ticket from being viewed directly
(http://trac.edgewall.org/ticket/7840). Fortunately, you can still see the
whole description (but none of the updates) here:

https://svn.boost.org/trac/boost/query?status=closed&summary=~thread_proxy&col=id&col=summary&col=status&col=owner&col=type&col=milestone&col=version&col=reporter&order=priority&row=description

Which I think matches what was was pasted here:

> The only platform on which I've used boost::thread is Linux + GCC.
> So, on the debugging front, I can only speak to that. In this
> configuration (using pthreads), the behavior of an exception being
> allowed to propagate outside of a thread function is quite useful -
> you get a backtrace of the entire call sequence leading up to the
> throw, AND a full unwind back from that point (which looks like
> further entries in the call stack).

Does anyone know if it also call std::terminate() ?

> A more troubling aspect of this try/catch block is that the thread
> terminates in exactly the same way via an otherwise unhandled
> exception as it does when the user-supplied threadfunc exits cleanly.
> If the user of boost::thread didn't think to catch the particular
> exception in question, then it's unlikely it employed and is
> inspecting any other mechanism for determining whether the thread
> accomplished its goal. This assumption violated, it's unsafe to
> assume the program will continue to function correctly.

I disagree. It is rare that an exception carries information that
determines how it needs to be handled. Usually, the same recovery
and/or unwinding actions apply to all exceptions.

> Since the thread exists in the same memory space as the rest of the
> process (and shares library state, if not also other data structures),
> an unhandled exception indicates bad state in the process, or some
> other invalidated assumption.

I don't think an unhandled exception means anything other than that
there was no handler to catch it.

> In fact, in non-exception-safe code, it may even produce bad state.
> Any of these conditions makes it unsafe to assume the program will
> continue to operate correctly.
>
> Finally, there's a more philosophical point that should probably be
> made. The primary purpose of exceptions is to provide proactive
> notification of program errors

If by "program errors" you mean "inability to satisfy postconditions, as
when necessary resources have been exhausted," then yes. If you mean
bugs, then no.

> (as opposed to relying on return codes - which facilitate errors being
> silently ignored). Why should behavior of uncaught exceptions in
> other threads be any different than main?

It should not. I think the author's assumption was that the system's
runtime library already provided the standard-mandated call to
terminate() when an exception escapes from main(), but since the
standard didn't say anything about thread-termination, one can't count
on a call to terminate() when an exception escapes from a thread.

> Yet thread_proxy() just quietly drops them on the floor.

I don't think there is a thread_proxy in the current Boost.Thread
anymore. At least, rgrep isn't finding it for me. And the existing
catch(...) blocks I did find call terminate().

> As a user, I normally expect that no
> unhandled exceptions were thrown, if my program runs to completion.
>
> WHAT WILL HAPPEN IF IT'S REMOVED?
>
> If the user specifically wants this behavior, it can suitably augment its
> user-supplied threadfunc to contain the catchall. There's nothing wrong with simply
> stating that the behavior of exceptions that propagate outside threadfunc is
> undefined.
>
> While changing this might "break" some existing code, it's really
> quite likely that code is already broken - though the user simply
> doesn't know it. IMO, there's nothing wrong with libraries evolving
> to detect more errors and invalid conditions.
>
>
> CONCLUSION
>
> In summary, I believe the current behavior is:
> 1. Dangerous - hides program errors in a most un-exception-like
> manner.
> 2. Unfriendly - defeats useful debugging functionality,
> on some platforms.
> 3. Surprising - users don't expect libraries to inhibit propagation
> of their exceptions.
> 4. Unnecessary - the user can easily supply this behavior,

I mostly agree. There's only the issue of ensuring calls to terminate
when the user want CD-conforming behavior, and as Peter D. points out,
on Win32/MSVC at least, that doesn't have to be an issue.

-- 
Dave Abrahams
BoostPro Computing
http://www.boostpro.com

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk