This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: catch(...) and forced unwind


Jason Merrill <jason@redhat.com> writes:

> On Mon, 15 Dec 2003 18:32:10 -0500, David Abrahams <dave@boost-consulting.com> wrote:
>
>> Jason Merrill <jason@redhat.com> writes:
>>
>> I have to admit I am not familiar with the specification of iostreams
>> - in fact, I try to avoid getting familiar with that part of the
>> standard. I have been going on the assumption that the specification
>> of badbit handling counts as "otherwise specified".  If I am wrong
>> (and I may be) then I take it all back.  Am I?  
>
>   27.6.1  Input streams                              [lib.input.streams]
>
> 2 Two  groups of member function signatures share common properties: the
>   formatted input functions (or extractors) and  the  unformatted  input
>   functions.  Both  groups  of input functions are described as if they
>   obtain (or extract) input characters by calling  rdbuf()->sbumpc()  or
>   rdbuf()->sgetc().  They may use other public members of istream.
>
> 3 If  rdbuf()->sbumpc()  or rdbuf()->sgetc() returns traits::eof(), then
>   the input function, except as explicitly  noted  otherwise,  completes
>   its    actions    and   does   setstate(eofbit),   which   may   throw
>   ios_base::failure (_lib.iostate.flags_), before returning.
>
> 4 If one of these called functions  throws  an  exception,  then  unless
>   explicitly  noted  otherwise,  the input function sets badbit in error
>   state.  If badbit is on in exceptions(), the input  function  rethrows 
>   the exception without  completing its  actions, otherwise  it does not
>   throw anything and proceeds as if the called function had  returned  a
>   failure indication.
>
> The text for output streams is similar.  I note, though I concede that this
> is something of a perverse reading of the standard, that although this says
> that the functions don't rethrow, nothing precludes them from throwing
> implementation-defined exceptions of their own.

I think that's beyond perverse.  The language is clear: "otherwise it
does not throw anything".  That precludes any throwing whatsoever,
unless of course I've misread that text and paragraph 4 is only
describing one corner of the behavior while exceptions are allowed to
escape under other conditions.

> Also, this restriction only applies to the {un,}formatted i/o functions,
> not to any other operations.
>
> I would like to loosen the passage quoted above to allow rethrowing some
> exceptions as defined by the implementation.  I don't think this change
> would break anyone's code, since the existing guarantee is so weak.

I don't think that's a safe conclusion.  There's plenty of legacy code
which acts as though there is no such thing as an exception.  You can
pretty much do all the iostream-ing you want under that assumption,
since they are handed to you out of the box in that state.  One
obvious place output streaming might be done is in an object's
destructor, for logging purposes.  It seems entirely plausible that
people might scatter local objects throughout throughout functions in
order to do tracing.  If thread cancellation is picked up by an output
streaming call in a destructor during unwinding, we'll go directly to
terminate (boom).

>>> Actually, this is backwards -- the standard doesn't allow the C I/O
>>> functions to throw any exceptions; see the passage above.  This obviously
>>> needs to change if we're going to do anything useful with POSIX thread
>>> cancellation.
>
>> Not sure what "anything useful" means.
>
> If all of the cancellation points are throw(), 

well, then they're not cancellation points anymore, are they?

> the cancellation exception can't propagate, so we can't run any
> cleanups.  Which isn't very useful.

It's obvious that unwinding due to cancellation has to be possible.
[I presume there's a function people can call to explicitly induce
unwinding when the thread is cancelled?]  The question is whether it's
appropriate to force unwinding in this one particular case where users
have been given license to assume there will be none.

> I certainly don't see the termination compromise as The Right Thing.  It's
> just that in the previous discussion, we failed to reach agreement as to
> what ought to happen when a catch(...) block doesn't rethrow a cancellation
> exception.  Termination makes nobody happy, but it means that any eventual
> resolution is a pure extension; nobody has written code that will break
> when the semantics change.

Makes sense now that you explain it.

>>> And that we might have to adjust a few things to make that work?
>>
>> Yes.  The only things I think are crucial here is that functions which
>> are specified not to throw (or conditions which are specified not to
>> throw) continue to not throw anything, including cancellation, and
>> that whatever guarantees functions give about program state in case
>> they throw an exception also apply if the exception is a thread
>> cancellation.  Almost without exception (NPI), code that works in the
>> presence of exceptions does not depend on the meaning of said
>> exceptions, so giving cancellation exceptions any kind of special
>> license to violate assumptions made about other exceptions would be
>> wrong.
>
> I am sympathetic to this position.
>
>>>> In the meantime, the ISO committee is discussing a standard threads
>>>> library for C++, including a cancellation model incompatible with what
>>>> is being proposed here.  It would be better for everybody involved for 
>>>> Gcc to match it.
>>>
>>> Please elaborate.  I don't see a relevant paper in any of the recent
>>> mailings.
>>
>> There ain't nothin'.  The effort to standardize Boost.Threads has been
>> languishing :(
>
> Well, can either of you give a brief sketch of the Boost.Threads
> cancellation model?  

I'm afraid http://www.boost.org/libs/thread/doc/faq.html#question8 is
all I can offer, which isn't much help.  The reason it's been
languishing is that the author/maintainer seems to have evaporated,
so I don't know if we'll be able to find out much more, but I've
cc:'d him.

> Has David Butenhof been involved at all?  He seems to have been
> thinking about the interaction of threads and exceptions longer than
> anyone else.

Yes, though not directly.  Bill Kempf (the Boost.Threads guy)
communicated with him and extensively read his writings on the subject
before he vaporized.  My understanding, from everything I've read, is
that David Butenhof believes that *any* asynchronous (forced, not
under user control) cancellation model is wrong.  IIRC there's
something like that in pthreads and he regrets it.  But rather than
speaking for him, I should let him speak for himself.

  http://tinyurl.com/zg5d

Plus, we can ask him questions.  He's quite approachable, I've found.

The one place I have to pre-emptively disagree with him is (from the
first link):

   "NOBODY has any business "finalizing" (catching and not 
    releasing) an exception they don't know by name. If you can't identify the 
    exception, you can't know why it was raised or what it means. And if you 
    don't understand what it means, you cannot possibly know that it doesn't 
    need to be handled further down the stack."

Not all code is exception-safe, and not all languages can handle C++
exceptions.  At the boundaries between exception-safe code and
everything else, catch(...) is appropriate.

-- 
Dave Abrahams
Boost Consulting
www.boost-consulting.com


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]