Topic: Unexit" via exception?


Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1997/04/15
Raw View

Andrew Gierth wrote:
>
> >>>>> "Christopher" == Christopher Eltschka <celtschk@physik.tu-muenchen.de>
> writes:
>
>  Christopher> However, next try :-)
>
>  Christopher> void sorry()
>  Christopher> {
>  Christopher>   throw "Sorry, but I won't let you go!";
>  Christopher> }
>
>  Christopher> int main()
>  Christopher> {
>  Christopher>   set_terminate(sorry);
>
>   18.6.3.1  Type terminate_handler               [lib.terminate.handler]
>
>   typedef void (*terminate_handler)();
>
> 1 The type of a handler function to be called by terminate() when termi-
>   nating exception processing.
>   Required behavior:
>     A terminate_handler shall terminate execution of the program without
>     returning to the caller.
>   Default behavior:
>     The implementation's default terminate_handler calls abort().
>
> Your sorry() function doesn't terminate the program, therefore it is
> not conforming.

This still doesn't say what should happen. Leaving it undefined is
IMHO the worst possible option, as exceptions can (are designed to)
propagate through function calls, so such a situation may occur
without notice (before the exception is actually thrown at runtime,
of course).

BTW, let's "fix" the example:

void cleanup() throw()
{
  throw "Sorry."
}

void sorry2()
{
  cleanup(); // because of the throw(), cleanup can't return via
             // exception!
  abort();   // terminates the program, so no return
}

void sorry()
{
  throw "Sorry, but I won't let you go!";
}

int main()
{
  set_terminate(sorry2); // sorry2 _is_ conforming
  atexit(sorry);
  cout << "Now we leave (really?)";
} // now exit(0) will be called implicitly...

So what happens now:

exit calls sorry, which throws, so terminate is called.
Terminate calls sorry2, which calls cleanup.
cleanup throws, but this throw is caucht by the throw() specification,
so unexpected is called, which itself calls - terminate!
Now, does terminate call sorry2 again (thus producing an infinite
recursion), or does it "unregister" sorry2 before the first call,
and call abort on the second call? (I hope the second).

And remember that cleanup could be inside a library without source;
and calling it seems perfectly safe because of the throw().
Besides that, any function called by cleanup itself might have
this throw() specification.

Another point:

What happens if you call exit from terminate (which might have been
called while exit was active)?
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Alexandre Oliva <oliva@dcc.unicamp.br>
Date: 1997/04/17
Raw View

Christopher Eltschka writes:

[snip]
> int main()
> {
>   set_terminate(sorry);
>   atexit(sorry);
[snip]

> Again exit will call sorry, which throws, so terminate is called.
> But this time, terminate calls sorry as well, which again throws.
> What now?

Setting sorry as the terminate_handler invokes undefined behavior,
since the CD2 requires a terminate_handler to terminate the execution
of the program without returning to the caller.  Even if you argue
that throwing an exception is not returning to the caller, the handler
*must* terminate the execution of the program; if it fails to do so,
undefined behavior arises, and you're on your own.

--
Alexandre Oliva
mailto:oliva@dcc.unicamp.br mailto:aoliva@acm.org
Universidade Estadual de Campinas, SP, Brasil
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Andrew Gierth <andrew@erlenstar.demon.co.uk>
Date: 1997/04/13
Raw View

>>>>> "Christopher" == Christopher Eltschka <celtschk@physik.tu-muenchen.de>
writes:

 Christopher> However, next try :-)

 Christopher> void sorry()
 Christopher> {
 Christopher>   throw "Sorry, but I won't let you go!";
 Christopher> }

 Christopher> int main()
 Christopher> {
 Christopher>   set_terminate(sorry);

  18.6.3.1  Type terminate_handler               [lib.terminate.handler]

  typedef void (*terminate_handler)();

1 The type of a handler function to be called by terminate() when termi-
  nating exception processing.
  Required behavior:
    A terminate_handler shall terminate execution of the program without
    returning to the caller.
  Default behavior:
    The implementation's default terminate_handler calls abort().

Your sorry() function doesn't terminate the program, therefore it is
not conforming.

--
Andrew.
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1997/04/11
Raw View
Andrew Gierth wrote:
>
> >>>>> "Christopher" == Christopher Eltschka <celtschk@physik.tu-muenchen.de>
> writes:
>
>  Christopher> Now if use atexit to install an exit handler, which
>  Christopher> itself throws an exception, would I then return to the
>  Christopher> caller of exit (as the block is not left)?
>
> 15.5.1  The terminate() function                    [except.terminate]
>
> 1 In  the  following situations exception handling must be abandoned for
>   less subtle error handling techniques:
>   [...]
>   --when execution of a function registered with atexit exits  using  an
>     exception (_lib.support.start.term_), or
>   [...]
>
> 2 In such cases,
>           void terminate();
>   is called (_lib.exception.terminate_).

Ah, this was what I didn't find.
However, next try :-)

void sorry()
{
  throw "Sorry, but I won't let you go!";
}

int main()
{
  set_terminate(sorry);
  atexit(sorry);
  cout << "Now let's try to exit!";
  try
  {
    exit(1);
  }
  catch(...)
  {
    cout << "Oops!" << endl;
  }
  cout << "Now we leave (really?)";
} // now exit(0) will be called implicitly...

Again exit will call sorry, which throws, so terminate is called.
But this time, terminate calls sorry as well, which again throws.
What now?
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1997/04/09
Raw View
In 3.6.1 [basic.start.main], I found the following:

4 Calling the function
          void exit(int);
  declared in <cstdlib> (_lib.support.start.term_) terminates  the  pro-
  gram  without  leaving  the current block and hence without destroying
  any objects with automatic storage duration (_class.dtor_).   If  exit
[...]

Now if use atexit to install an exit handler, which itself throws an
exception, would I then return to the caller of exit (as the block
is not left)?
For example:

void sorry()
{
  throw "Sorry, but I won't let you go!";
}

int main()
{
  atexit(sorry);
  cout << "Now let's try to exit!";
  try
  {
    exit(1);
  }
  catch(...)
  {
    cout << "Oops!" << endl;
  }
  cout << "Now we leave (really?)";
} // now exit(0) will be called implicitly...

Now, what would this program do according to the current draft?
(with g++ it just core dumps, but that's of course no standard behaviour
- it might be undefined, of course)

IMHO it should not return to the caller of exit (there might have been
called other atexit installed functions, or static object destruction),
but I don't find anything about exceptions after calling exit.
(A similar problem arises if destructors of static objects throw)

Adding a throw() to the definition of exit should work, I guess.
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Andrew Gierth <andrew@erlenstar.demon.co.uk>
Date: 1997/04/09
Raw View
>>>>> "Christopher" == Christopher Eltschka <celtschk@physik.tu-muenchen.de>
writes:

 Christopher> Now if use atexit to install an exit handler, which
 Christopher> itself throws an exception, would I then return to the
 Christopher> caller of exit (as the block is not left)?

15.5.1  The terminate() function                    [except.terminate]

1 In  the  following situations exception handling must be abandoned for
  less subtle error handling techniques:
  [...]
  --when execution of a function registered with atexit exits  using  an
    exception (_lib.support.start.term_), or
  [...]

2 In such cases,
          void terminate();
  is called (_lib.exception.terminate_).

--
Andrew.
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]