mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-30 08:21:25 +00:00
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:
parent
f60e075ac5
commit
59fed7cd35
3 changed files with 85 additions and 35 deletions
|
@ -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>
|
2005-06-30 Richard Frith-Macdonald <rfm@gnu.org>
|
||||||
|
|
||||||
* Source/NSSerializer.m: deserializeFromInfo() check that cross
|
* Source/NSSerializer.m: deserializeFromInfo() check that cross
|
||||||
|
|
|
@ -79,36 +79,17 @@ NSString* const NSParseErrorException
|
||||||
|
|
||||||
#include "GSPrivate.h"
|
#include "GSPrivate.h"
|
||||||
|
|
||||||
static void
|
static void _terminate()
|
||||||
_preventRecursion (NSException *exception)
|
|
||||||
{
|
{
|
||||||
fprintf(stderr, "recursion encountered handling uncaught exception\n");
|
BOOL shouldAbort;
|
||||||
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
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
a = YES; // abort() by default.
|
shouldAbort = YES; // abort() by default.
|
||||||
#else
|
#else
|
||||||
a = NO; // exit() by default.
|
shouldAbort = NO; // exit() by default.
|
||||||
#endif
|
#endif
|
||||||
a = GSEnvironmentFlag("CRASH_ON_ABORT", a);
|
shouldAbort = GSEnvironmentFlag("CRASH_ON_ABORT", shouldAbort);
|
||||||
if (a == YES)
|
if (shouldAbort == YES)
|
||||||
{
|
{
|
||||||
abort();
|
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>
|
<p>
|
||||||
The <code>NSException</code> class helps manage errors in a program. It
|
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
|
Raises the exception. All code following the raise will not be
|
||||||
executed and program control will be transfered to the closest
|
executed and program control will be transfered to the closest
|
||||||
calling method which encapsulates the exception code in an
|
calling method which encapsulates the exception code in an
|
||||||
NS_DURING macro, or to the uncaught exception handler if there is no
|
NS_DURING macro.<br />
|
||||||
other handling code.
|
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
|
- (void) raise
|
||||||
{
|
{
|
||||||
NSThread *thread;
|
NSThread *thread;
|
||||||
NSHandler *handler;
|
NSHandler *handler;
|
||||||
|
|
||||||
if (_NSUncaughtExceptionHandler == NULL)
|
|
||||||
{
|
|
||||||
_NSUncaughtExceptionHandler = _NSFoundationUncaughtExceptionHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
thread = GSCurrentThread();
|
thread = GSCurrentThread();
|
||||||
handler = thread->_exception_handler;
|
handler = thread->_exception_handler;
|
||||||
if (handler == NULL)
|
if (handler == NULL)
|
||||||
{
|
{
|
||||||
_NSUncaughtExceptionHandler(self);
|
static BOOL recursion = NO;
|
||||||
return;
|
|
||||||
|
/*
|
||||||
|
* 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;
|
thread->_exception_handler = handler->next;
|
||||||
|
|
|
@ -6,6 +6,12 @@
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
|
|
||||||
|
static void uncaught(NSException* e)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "In uncaught exception handler.\n");
|
||||||
|
[NSException raise: NSGenericException format: @"Recursive exception"];
|
||||||
|
}
|
||||||
|
|
||||||
static void test1(void)
|
static void test1(void)
|
||||||
{
|
{
|
||||||
NSURL *baseURL = [NSURL fileURLWithPath:@"/usr/local/bin"];
|
NSURL *baseURL = [NSURL fileURLWithPath:@"/usr/local/bin"];
|
||||||
|
@ -138,7 +144,15 @@ int main ()
|
||||||
|
|
||||||
printf ("Hello from object at 0x%x\n", (unsigned)[o self]);
|
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 release];
|
||||||
o = [NSString stringWithFormat: @"/proc/%d/status", getpid()];
|
o = [NSString stringWithFormat: @"/proc/%d/status", getpid()];
|
||||||
|
@ -146,6 +160,10 @@ int main ()
|
||||||
o = [NSString stringWithContentsOfFile: o];
|
o = [NSString stringWithContentsOfFile: o];
|
||||||
NSLog(@"'%@'", 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);
|
exit (0);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue