Fix buggy behavior where if the uncaught exception handler was set to a

function which returned, the -raise method could return.


git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@21389 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-Macdonald 2005-07-01 08:53:32 +00:00
parent 20887bf59c
commit a7f1ff64f9
3 changed files with 85 additions and 35 deletions

View file

@ -1,3 +1,11 @@
2005-07-01 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSException.m: ([-raise]) Fix behavior to be the same as in
MacOS-X (ie call the default uncaught exception handler after
whatever handler is set, in case the set handler does not terminate).
Ensures that the -raise method cannot return.
* Testing/basic.m: Add test for uncaught exception handler.
2005-06-30 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSSerializer.m: deserializeFromInfo() check that cross

View file

@ -79,36 +79,17 @@ NSString* const NSParseErrorException
#include "GSPrivate.h"
static void
_preventRecursion (NSException *exception)
static void _terminate()
{
fprintf(stderr, "recursion encountered handling uncaught exception\n");
fflush(stderr); /* NEEDED UNDER MINGW */
}
static void
_NSFoundationUncaughtExceptionHandler (NSException *exception)
{
BOOL a;
extern const char* GSArgZero(void);
_NSUncaughtExceptionHandler = _preventRecursion;
#if 1
fprintf(stderr, "%s: Uncaught exception %s, reason: %s\n", GSArgZero(),
[[exception name] lossyCString], [[exception reason] lossyCString]);
fflush(stderr); /* NEEDED UNDER MINGW */
#else
NSLog("Uncaught exception %@, reason: %@",
[exception name], [exception reason]);
#endif
BOOL shouldAbort;
#ifdef DEBUG
a = YES; // abort() by default.
shouldAbort = YES; // abort() by default.
#else
a = NO; // exit() by default.
shouldAbort = NO; // exit() by default.
#endif
a = GSEnvironmentFlag("CRASH_ON_ABORT", a);
if (a == YES)
shouldAbort = GSEnvironmentFlag("CRASH_ON_ABORT", shouldAbort);
if (shouldAbort == YES)
{
abort();
}
@ -118,6 +99,18 @@ _NSFoundationUncaughtExceptionHandler (NSException *exception)
}
}
static void
_NSFoundationUncaughtExceptionHandler (NSException *exception)
{
extern const char* GSArgZero(void);
fprintf(stderr, "%s: Uncaught exception %s, reason: %s\n", GSArgZero(),
[[exception name] lossyCString], [[exception reason] lossyCString]);
fflush(stderr); /* NEEDED UNDER MINGW */
_terminate();
}
/**
<p>
The <code>NSException</code> class helps manage errors in a program. It
@ -223,25 +216,56 @@ _NSFoundationUncaughtExceptionHandler (NSException *exception)
Raises the exception. All code following the raise will not be
executed and program control will be transfered to the closest
calling method which encapsulates the exception code in an
NS_DURING macro, or to the uncaught exception handler if there is no
other handling code.
NS_DURING macro.<br />
If the exception was not caught in a macro, the currently set
uncaught exception handler is called to perform final logging
and handle program termination.<br />
If the uncaught exception handler fails to terminate the program,
then the default builtin uncaught exception handler will do so.<br />
NB. all other exception raising methods call this one, so if you
want to set a breakpoint when debugging, set it in this method.
*/
- (void) raise
{
NSThread *thread;
NSHandler *handler;
if (_NSUncaughtExceptionHandler == NULL)
{
_NSUncaughtExceptionHandler = _NSFoundationUncaughtExceptionHandler;
}
thread = GSCurrentThread();
handler = thread->_exception_handler;
if (handler == NULL)
{
_NSUncaughtExceptionHandler(self);
return;
static BOOL recursion = NO;
/*
* Set a flag to prevent recursive uncaught exceptions.
*/
if (recursion == NO)
{
recursion = YES;
}
else
{
fprintf(stderr,
"recursion encountered handling uncaught exception\n");
fflush(stderr); /* NEEDED UNDER MINGW */
_terminate();
}
/*
* Call the uncaught exception handler (if there is one).
*/
if (_NSUncaughtExceptionHandler != NULL)
{
(*_NSUncaughtExceptionHandler)(self);
}
/*
* The uncaught exception handler which is set has not
* exited, so we call the builtin handler, (undocumented
* behavior of MacOS-X).
* The standard handler is guaranteed to exit/abort.
*/
_NSFoundationUncaughtExceptionHandler(self);
}
thread->_exception_handler = handler->next;

View file

@ -6,6 +6,12 @@
#if 1
static void uncaught(NSException* e)
{
fprintf(stderr, "In uncaught exception handler.\n");
[NSException raise: NSGenericException format: @"Recursive exception"];
}
static void test1(void)
{
NSURL *baseURL = [NSURL fileURLWithPath:@"/usr/local/bin"];
@ -138,7 +144,15 @@ int main ()
printf ("Hello from object at 0x%x\n", (unsigned)[o self]);
NSLog(@"Value for foo is %@", [a valueForKey: @"foo"]);
NS_DURING
{
NSLog(@"Value for foo is %@", [a valueForKey: @"foo"]);
}
NS_HANDLER
{
NSLog(@"Caught expected exception: %@", localException);
}
NS_ENDHANDLER
[o release];
o = [NSString stringWithFormat: @"/proc/%d/status", getpid()];
@ -146,6 +160,10 @@ int main ()
o = [NSString stringWithContentsOfFile: o];
NSLog(@"'%@'", o);
NSLog(@"This test should now cause program termination after a recursive exception");
NSSetUncaughtExceptionHandler(uncaught);
[NSException raise: NSGenericException format: @"an artifical exception"];
exit (0);
}
#else