This is the mail archive of the
libc-alpha@sources.redhat.com
mailing list for the glibc project.
Cancellation while throwing exception
- From: Scott Lamb <slamb at slamb dot org>
- To: libc-alpha at sources dot redhat dot com
- Date: Sun, 25 Jan 2004 13:20:07 -0600
- Subject: Cancellation while throwing exception
I was just reading a document that claims C++ code should never throw
exceptions in destructors, because Bad Things could happen if one is
throwing while unwinding the stack due to another exception - you can't
have two simultaneous active exceptions, so either std::unexpected()
gets called, or maybe std::terminate() directly (don't remember exactly).
It occurred to me that under NPTL, this is essentially the same as
cancellation while throwing an exception. The attached test program
shows that indeed std::terminate() gets called.
Maybe cancellation should be disabled for the duration of exception
throwing?
Thanks,
Scott Lamb
/*
* $Id: test_cancellation_while_throwing.cc 544 2004-01-25 00:02:35Z slamb $
* Scott Lamb <slamb@slamb.org>
*
* Tests cancellation while throwing a C++ exception. This is likely to
* present problems for systems which implement cancellation as an exception,
* since only one exception can be active at once.
*
* Some test results:
*
* - Mac OS X Panther 10.3.2:
* Returns success. This is expected, since OS X does not implement
* cancellation as an exception.
*
* - HP Tru64 UNIX 5.1B:
* Resources lost(coredump)
*
* - Fedora Core 1, glibc 2.3.3-3, no LD_ASSUME_KERNEL:
* terminate called without an active exception
* Aborted
*
* - Fedora Core 1, glibc 2.3.3-3, LD_ASSUME_KERNEL=2.4.1:
* Returns success. Again, expected; cancellation is not an exception.
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <exception>
enum ErrorReturnType {
DIRECT,
ERRNO
};
void error_wrap(int retval, const char *funcname, ErrorReturnType type) {
if (type == ERRNO && retval < 0) {
fprintf(stderr, "%s returned %d (%s)\n",
funcname, errno, strerror(errno));
abort();
} else if (type == DIRECT && retval != 0) {
fprintf(stderr, "%s returned %d (%s)\n",
funcname, retval, strerror(retval));
abort();
}
}
class CancelInDestructor {
public:
CancelInDestructor() {}
~CancelInDestructor() {
error_wrap(pthread_cancel(pthread_self()), "pthread_cancel", DIRECT);
pthread_testcancel();
}
};
void* cancel_thread_main(void*) {
try {
CancelInDestructor cid;
throw 1;
} catch (int&) {}
return NULL;
}
int main() {
pthread_t cancel_thread;
#if __GNUC__ >= 3
std::set_terminate(__gnu_cxx::__verbose_terminate_handler);
#endif
error_wrap(pthread_create(&cancel_thread, NULL, &cancel_thread_main, NULL),
"pthread_create", DIRECT);
error_wrap(pthread_join(cancel_thread, NULL), "pthread_join", DIRECT);
return 0;
}