X-Git-Url: https://git.saurik.com/apple/objc4.git/blobdiff_plain/7c0e6487d7b67b6bf6c632300ee4b74e8950b051..7af964d1562d70f51a8e9aca24215ac3d83d0624:/test/exc.m diff --git a/test/exc.m b/test/exc.m new file mode 100644 index 0000000..2921351 --- /dev/null +++ b/test/exc.m @@ -0,0 +1,635 @@ +#include "test.h" +#include +#include + +static volatile int state = 0; +#define BAD 1000000 + +#if defined(USE_FOUNDATION) + +#include + +static NSAutoreleasePool *p; +void pool(void) { [p release]; p = [NSAutoreleasePool new]; } + +@interface Super : NSException @end +@implementation Super ++new { return [[self exceptionWithName:@"Super" reason:@"reason" userInfo:nil] retain]; } +-(void)check { state++; } ++(void)check { testassert(!"caught class object, not instance"); } +@end + +#else + +void pool(void) { } + +@interface Super { id isa; } @end +@implementation Super ++new { return class_createInstance(self, 0); } ++(void)initialize { } +-(void)check { state++; } ++(void)check { testassert(!"caught class object, not instance"); } +-(void)release { object_dispose(self); } +@end + +#endif + +@interface Sub : Super @end +@implementation Sub +@end + + +#if __OBJC2__ + +void altHandlerFail(id unused __unused, void *context __unused) +{ + fail("altHandlerFail called"); +} + +#define ALT_HANDLER(n) \ + void altHandler##n(id unused __unused, void *context) \ + { \ + testassert(context == (void*)&altHandler##n); \ + testassert(state == n); \ + state++; \ + } + +ALT_HANDLER(2) +ALT_HANDLER(3) +ALT_HANDLER(4) +ALT_HANDLER(5) +ALT_HANDLER(6) +ALT_HANDLER(7) + + +static void throwWithAltHandler(void) __attribute__((noinline)); +static void throwWithAltHandler(void) +{ + @try { + state++; + uintptr_t token = objc_addExceptionHandler(altHandler3, altHandler3); + // state++ inside alt handler + @throw [Super new]; + state = BAD; + objc_removeExceptionHandler(token); + } + @catch (Sub *e) { + state = BAD; + } + state = BAD; +} + + +static void throwWithAltHandlerAndRethrow(void) __attribute__((noinline)); +static void throwWithAltHandlerAndRethrow(void) +{ + @try { + state++; + uintptr_t token = objc_addExceptionHandler(altHandler3, altHandler3); + // state++ inside alt handler + @throw [Super new]; + state = BAD; + objc_removeExceptionHandler(token); + } + @catch (...) { + testassert(state == 4); + state++; + @throw; + } + state = BAD; +} + +#endif + + +int main() +{ + pool(); + + testprintf("try-catch-finally, exception caught exactly\n"); + + state = 0; + @try { + state++; + @try { + state++; + @throw [Super new]; + state = BAD; + } + @catch (Super *e) { + state++; + [e check]; // state++ + [e release]; + } + @finally { + state++; + } + state++; + } + @catch (...) { + state = BAD; + } + testassert(state == 6); + + + testprintf("try-finally, no exception thrown\n"); + + state = 0; + @try { + state++; + @try { + state++; + } + @finally { + state++; + } + state++; + } + @catch (...) { + state = BAD; + } + testassert(state == 4); + + + testprintf("try-finally, with exception\n"); + + state = 0; + @try { + state++; + @try { + state++; + @throw [Super new]; + state = BAD; + } + @finally { + state++; + } + state = BAD; + } + @catch (id e) { + state++; + [e check]; // state++ + [e release]; + } + testassert(state == 5); + + + testprintf("try-catch-finally, no exception\n"); + + state = 0; + @try { + state++; + @try { + state++; + } + @catch (...) { + state = BAD; + } + @finally { + state++; + } + state++; + } @catch (...) { + state = BAD; + } + testassert(state == 4); + + + testprintf("try-catch-finally, exception not caught\n"); + + state = 0; + @try { + state++; + @try { + state++; + @throw [Super new]; + state = BAD; + } + @catch (Sub *e) { + state = BAD; + } + @finally { + state++; + } + state = BAD; + } + @catch (id e) { + state++; + [e check]; // state++ + [e release]; + } + testassert(state == 5); + + + testprintf("try-catch-finally, exception caught exactly, rethrown\n"); + + state = 0; + @try { + state++; + @try { + state++; + @throw [Super new]; + state = BAD; + } + @catch (Super *e) { + state++; + [e check]; // state++ + @throw; + state = BAD; + } + @finally { + state++; + } + state = BAD; + } + @catch (id e) { + state++; + [e check]; // state++ + [e release]; + } + testassert(state == 7); + + + testprintf("try-catch, no exception\n"); + + state = 0; + @try { + state++; + @try { + state++; + } + @catch (...) { + state = BAD; + } + state++; + } @catch (...) { + state = BAD; + } + testassert(state == 3); + + + testprintf("try-catch, exception not caught\n"); + + state = 0; + @try { + state++; + @try { + state++; + @throw [Super new]; + state = BAD; + } + @catch (Sub *e) { + state = BAD; + } + state = BAD; + } + @catch (id e) { + state++; + [e check]; // state++ + [e release]; + } + testassert(state == 4); + + + testprintf("try-catch, exception caught exactly\n"); + + state = 0; + @try { + state++; + @try { + state++; + @throw [Super new]; + state = BAD; + } + @catch (Super *e) { + state++; + [e check]; // state++ + [e release]; + } + state++; + } + @catch (...) { + state = BAD; + } + testassert(state == 5); + + + testprintf("try-catch, exception caught exactly, rethrown\n"); + + state = 0; + @try { + state++; + @try { + state++; + @throw [Super new]; + state = BAD; + } + @catch (Super *e) { + state++; + [e check]; // state++ + @throw; + state = BAD; + } + state = BAD; + } + @catch (id e) { + state++; + [e check]; // state++ + [e release]; + } + testassert(state == 6); + + + testprintf("try-catch, exception caught exactly, thrown again explicitly\n"); + + state = 0; + @try { + state++; + @try { + state++; + @throw [Super new]; + state = BAD; + } + @catch (Super *e) { + state++; + [e check]; // state++ + @throw e; + state = BAD; + } + state = BAD; + } + @catch (id e) { + state++; + [e check]; // state++ + [e release]; + } + testassert(state == 6); + + + testprintf("try-catch, default catch, rethrown\n"); + + state = 0; + @try { + state++; + @try { + state++; + @throw [Super new]; + state = BAD; + } + @catch (...) { + state++; + @throw; + state = BAD; + } + state = BAD; + } + @catch (id e) { + state++; + [e check]; // state++ + [e release]; + } + testassert(state == 5); + + + testprintf("try-catch, default catch, rethrown and caught inside nested handler\n"); + + state = 0; + @try { + state++; + @try { + state++; + @throw [Super new]; + state = BAD; + } + @catch (...) { + state++; + + @try { + state++; + @throw; + state = BAD; + } @catch (Sub *e) { + state = BAD; + } @catch (Super *e) { + state++; + [e check]; // state++ + [e release]; + } @catch (...) { + state = BAD; + } @finally { + state++; + } + + state++; + } + state++; + } + @catch (...) { + state = BAD; + } + testassert(state == 9); + + + testprintf("try-catch, default catch, rethrown inside nested handler but not caught\n"); + + state = 0; + @try { + state++; + @try { + state++; + @throw [Super new]; + state = BAD; + } + @catch (...) { + state++; + + @try { + state++; + @throw; + state = BAD; + } @catch (Sub *e) { + state = BAD; + } @finally { + state++; + } + + state = BAD; + } + state = BAD; + } + @catch (id e) { + state++; + [e check]; // state++ + [e release]; + } + testassert(state == 7); + +#if __OBJC2__ + // alt handlers + // run a lot to catch failed unregistration (runtime complains at 1000) +#define ALT_HANDLER_REPEAT 2000 + int i; + + testprintf("alt handler, no exception\n"); + + for (i = 0; i < ALT_HANDLER_REPEAT; i++) { + pool(); + + state = 0; + @try { + state++; + @try { + uintptr_t token = objc_addExceptionHandler(altHandlerFail, 0); + state++; + objc_removeExceptionHandler(token); + } + @catch (...) { + state = BAD; + } + state++; + } @catch (...) { + state = BAD; + } + testassert(state == 3); + } + + testprintf("alt handler, exception thrown through\n"); + + for (i = 0; i < ALT_HANDLER_REPEAT; i++) { + pool(); + + state = 0; + @try { + state++; + @try { + state++; + uintptr_t token = objc_addExceptionHandler(altHandler2, altHandler2); + // state++ inside alt handler + @throw [Super new]; + state = BAD; + objc_removeExceptionHandler(token); + } + @catch (Sub *e) { + state = BAD; + } + state = BAD; + } + @catch (id e) { + testassert(state == 3); + state++; + [e check]; // state++ + [e release]; + } + testassert(state == 5); + } + + + testprintf("alt handler, nested\n"); + + for (i = 0; i < ALT_HANDLER_REPEAT; i++) { + pool(); + + state = 0; + @try { + state++; + @try { + state++; + // same-level handlers called in FIFO order (not stack-like) + uintptr_t token = objc_addExceptionHandler(altHandler4, altHandler4); + // state++ inside alt handler + uintptr_t token2 = objc_addExceptionHandler(altHandler5, altHandler5); + // state++ inside alt handler + throwWithAltHandler(); // state += 2 inside + state = BAD; + objc_removeExceptionHandler(token); + objc_removeExceptionHandler(token2); + } + @catch (id e) { + testassert(state == 6); + state++; + [e check]; // state++; + [e release]; + } + state++; + } + @catch (...) { + state = BAD; + } + testassert(state == 9); + } + + + testprintf("alt handler, nested, rethrows in between\n"); + + for (i = 0; i < ALT_HANDLER_REPEAT; i++) { + pool(); + + state = 0; + @try { + state++; + @try { + state++; + // same-level handlers called in FIFO order (not stack-like) + uintptr_t token = objc_addExceptionHandler(altHandler5, altHandler5); + // state++ inside alt handler + uintptr_t token2 = objc_addExceptionHandler(altHandler6, altHandler6); + // state++ inside alt handler + throwWithAltHandlerAndRethrow(); // state += 3 inside + state = BAD; + objc_removeExceptionHandler(token); + objc_removeExceptionHandler(token2); + } + @catch (...) { + testassert(state == 7); + state++; + @throw; + } + state = BAD; + } + @catch (id e) { + testassert(state == 8); + state++; + [e check]; // state++ + [e release]; + } + testassert(state == 10); + } + + + testprintf("alt handler, exception thrown and caught inside\n"); + + for (i = 0; i < ALT_HANDLER_REPEAT; i++) { + pool(); + + state = 0; + @try { + state++; + uintptr_t token = objc_addExceptionHandler(altHandlerFail, 0); + @try { + state++; + @throw [Super new]; + state = BAD; + } + @catch (Super *e) { + state++; + [e check]; // state++ + [e release]; + } + state++; + objc_removeExceptionHandler(token); + } + @catch (...) { + state = BAD; + } + testassert(state == 5); + } + +#endif + +#if defined(USE_FOUNDATION) + [p release]; + succeed("nsexc.m"); +#else + succeed("exc.m"); +#endif +}