]> git.saurik.com Git - apple/objc4.git/blob - test/exc.m
objc4-532.2.tar.gz
[apple/objc4.git] / test / exc.m
1 /*
2 llvm-gcc unavoidably warns about our deliberately out-of-order handlers
3
4 TEST_BUILD_OUTPUT
5 .*exc.m: In function .*
6 .*exc.m:\d+: warning: exception of type .* will be caught
7 .*exc.m:\d+: warning: by earlier handler for .*
8 .*exc.m:\d+: warning: exception of type .* will be caught
9 .*exc.m:\d+: warning: by earlier handler for .*
10 .*exc.m:\d+: warning: exception of type .* will be caught
11 .*exc.m:\d+: warning: by earlier handler for .*
12 OR
13 END
14 */
15
16 #include "test.h"
17 #include "testroot.i"
18 #include <objc/runtime.h>
19 #include <objc/objc-exception.h>
20
21 static volatile int state = 0;
22 #define BAD 1000000
23
24 #if defined(USE_FOUNDATION)
25
26 #include <Foundation/Foundation.h>
27
28 @interface Super : NSException @end
29 @implementation Super
30 +(id)exception { return AUTORELEASE([[self alloc] initWithName:@"Super" reason:@"reason" userInfo:nil]); }
31 -(void)check { state++; }
32 +(void)check { testassert(!"caught class object, not instance"); }
33 @end
34
35 #define FILENAME "nsexc.m"
36
37 #else
38
39 @interface Super : TestRoot @end
40 @implementation Super
41 +(id)exception { return AUTORELEASE([self new]); }
42 -(void)check { state++; }
43 +(void)check { testassert(!"caught class object, not instance"); }
44 @end
45
46 #define FILENAME "exc.m"
47
48 #endif
49
50 @interface Sub : Super @end
51 @implementation Sub
52 @end
53
54
55 #if __OBJC2__ && !TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE
56 void altHandlerFail(id unused __unused, void *context __unused)
57 {
58 fail("altHandlerFail called");
59 }
60
61 #define ALT_HANDLER(n) \
62 void altHandler##n(id unused __unused, void *context) \
63 { \
64 testassert(context == (void*)&altHandler##n); \
65 testassert(state == n); \
66 state++; \
67 }
68
69 ALT_HANDLER(1)
70 ALT_HANDLER(2)
71 ALT_HANDLER(3)
72 ALT_HANDLER(4)
73 ALT_HANDLER(5)
74 ALT_HANDLER(6)
75 ALT_HANDLER(7)
76
77
78 static void throwWithAltHandler(void) __attribute__((noinline));
79 static void throwWithAltHandler(void)
80 {
81 @try {
82 state++;
83 uintptr_t token = objc_addExceptionHandler(altHandler3, (void*)altHandler3);
84 // state++ inside alt handler
85 @throw [Super exception];
86 state = BAD;
87 objc_removeExceptionHandler(token);
88 }
89 @catch (Sub *e) {
90 state = BAD;
91 }
92 state = BAD;
93 }
94
95
96 static void throwWithAltHandlerAndRethrow(void) __attribute__((noinline));
97 static void throwWithAltHandlerAndRethrow(void)
98 {
99 @try {
100 state++;
101 uintptr_t token = objc_addExceptionHandler(altHandler3, (void*)altHandler3);
102 // state++ inside alt handler
103 @throw [Super exception];
104 state = BAD;
105 objc_removeExceptionHandler(token);
106 }
107 @catch (...) {
108 testassert(state == 4);
109 state++;
110 @throw;
111 }
112 state = BAD;
113 }
114
115 #endif
116
117 #if __cplusplus && __OBJC2__
118 #include <exception>
119 void terminator() {
120 succeed(FILENAME);
121 }
122 #endif
123
124
125 int main()
126 {
127 PUSH_POOL {
128
129 testprintf("try-catch-finally, exception caught exactly\n");
130
131 state = 0;
132 @try {
133 state++;
134 @try {
135 state++;
136 @throw [Super exception];
137 state = BAD;
138 }
139 @catch (Super *e) {
140 state++;
141 [e check]; // state++
142 }
143 @finally {
144 state++;
145 }
146 state++;
147 }
148 @catch (...) {
149 state = BAD;
150 }
151 testassert(state == 6);
152
153
154 testprintf("try-finally, no exception thrown\n");
155
156 state = 0;
157 @try {
158 state++;
159 @try {
160 state++;
161 }
162 @finally {
163 state++;
164 }
165 state++;
166 }
167 @catch (...) {
168 state = BAD;
169 }
170 testassert(state == 4);
171
172
173 testprintf("try-finally, with exception\n");
174
175 state = 0;
176 @try {
177 state++;
178 @try {
179 state++;
180 @throw [Super exception];
181 state = BAD;
182 }
183 @finally {
184 state++;
185 }
186 state = BAD;
187 }
188 @catch (id e) {
189 state++;
190 [e check]; // state++
191 }
192 testassert(state == 5);
193
194
195 testprintf("try-catch-finally, no exception\n");
196
197 state = 0;
198 @try {
199 state++;
200 @try {
201 state++;
202 }
203 @catch (...) {
204 state = BAD;
205 }
206 @finally {
207 state++;
208 }
209 state++;
210 } @catch (...) {
211 state = BAD;
212 }
213 testassert(state == 4);
214
215
216 testprintf("try-catch-finally, exception not caught\n");
217
218 state = 0;
219 @try {
220 state++;
221 @try {
222 state++;
223 @throw [Super exception];
224 state = BAD;
225 }
226 @catch (Sub *e) {
227 state = BAD;
228 }
229 @finally {
230 state++;
231 }
232 state = BAD;
233 }
234 @catch (id e) {
235 state++;
236 [e check]; // state++
237 }
238 testassert(state == 5);
239
240
241 testprintf("try-catch-finally, exception caught exactly, rethrown\n");
242
243 state = 0;
244 @try {
245 state++;
246 @try {
247 state++;
248 @throw [Super exception];
249 state = BAD;
250 }
251 @catch (Super *e) {
252 state++;
253 [e check]; // state++
254 @throw;
255 state = BAD;
256 }
257 @finally {
258 state++;
259 }
260 state = BAD;
261 }
262 @catch (id e) {
263 state++;
264 [e check]; // state++
265 }
266 testassert(state == 7);
267
268
269 testprintf("try-catch, no exception\n");
270
271 state = 0;
272 @try {
273 state++;
274 @try {
275 state++;
276 }
277 @catch (...) {
278 state = BAD;
279 }
280 state++;
281 } @catch (...) {
282 state = BAD;
283 }
284 testassert(state == 3);
285
286
287 testprintf("try-catch, exception not caught\n");
288
289 state = 0;
290 @try {
291 state++;
292 @try {
293 state++;
294 @throw [Super exception];
295 state = BAD;
296 }
297 @catch (Sub *e) {
298 state = BAD;
299 }
300 state = BAD;
301 }
302 @catch (id e) {
303 state++;
304 [e check]; // state++
305 }
306 testassert(state == 4);
307
308
309 testprintf("try-catch, exception caught exactly\n");
310
311 state = 0;
312 @try {
313 state++;
314 @try {
315 state++;
316 @throw [Super exception];
317 state = BAD;
318 }
319 @catch (Super *e) {
320 state++;
321 [e check]; // state++
322 }
323 state++;
324 }
325 @catch (...) {
326 state = BAD;
327 }
328 testassert(state == 5);
329
330
331 testprintf("try-catch, exception caught exactly, rethrown\n");
332
333 state = 0;
334 @try {
335 state++;
336 @try {
337 state++;
338 @throw [Super exception];
339 state = BAD;
340 }
341 @catch (Super *e) {
342 state++;
343 [e check]; // state++
344 @throw;
345 state = BAD;
346 }
347 state = BAD;
348 }
349 @catch (id e) {
350 state++;
351 [e check]; // state++
352 }
353 testassert(state == 6);
354
355
356 testprintf("try-catch, exception caught exactly, thrown again explicitly\n");
357
358 state = 0;
359 @try {
360 state++;
361 @try {
362 state++;
363 @throw [Super exception];
364 state = BAD;
365 }
366 @catch (Super *e) {
367 state++;
368 [e check]; // state++
369 @throw e;
370 state = BAD;
371 }
372 state = BAD;
373 }
374 @catch (id e) {
375 state++;
376 [e check]; // state++
377 }
378 testassert(state == 6);
379
380
381 testprintf("try-catch, default catch, rethrown\n");
382
383 state = 0;
384 @try {
385 state++;
386 @try {
387 state++;
388 @throw [Super exception];
389 state = BAD;
390 }
391 @catch (...) {
392 state++;
393 @throw;
394 state = BAD;
395 }
396 state = BAD;
397 }
398 @catch (id e) {
399 state++;
400 [e check]; // state++
401 }
402 testassert(state == 5);
403
404
405 testprintf("try-catch, default catch, rethrown and caught inside nested handler\n");
406
407 state = 0;
408 @try {
409 state++;
410 @try {
411 state++;
412 @throw [Super exception];
413 state = BAD;
414 }
415 @catch (...) {
416 state++;
417
418 @try {
419 state++;
420 @throw;
421 state = BAD;
422 } @catch (Sub *e) {
423 state = BAD;
424 } @catch (Super *e) {
425 state++;
426 [e check]; // state++
427 } @catch (...) {
428 state = BAD;
429 } @finally {
430 state++;
431 }
432
433 state++;
434 }
435 state++;
436 }
437 @catch (...) {
438 state = BAD;
439 }
440 testassert(state == 9);
441
442
443 testprintf("try-catch, default catch, rethrown inside nested handler but not caught\n");
444
445 state = 0;
446 @try {
447 state++;
448 @try {
449 state++;
450 @throw [Super exception];
451 state = BAD;
452 }
453 @catch (...) {
454 state++;
455
456 @try {
457 state++;
458 @throw;
459 state = BAD;
460 }
461 @catch (Sub *e) {
462 state = BAD;
463 }
464 @finally {
465 state++;
466 }
467
468 state = BAD;
469 }
470 state = BAD;
471 }
472 @catch (id e) {
473 state++;
474 [e check]; // state++
475 }
476 testassert(state == 7);
477
478
479 #if __cplusplus && __OBJC2__
480 testprintf("C++ try/catch, Objective-C exception superclass\n");
481
482 state = 0;
483 try {
484 state++;
485 try {
486 state++;
487 try {
488 state++;
489 @throw [Super exception];
490 state = BAD;
491 } catch (...) {
492 state++;
493 throw;
494 state = BAD;
495 }
496 state = BAD;
497 } catch (void *e) {
498 state = BAD;
499 } catch (int e) {
500 state = BAD;
501 } catch (Sub *e) {
502 state = BAD;
503 } catch (Super *e) {
504 state++;
505 [e check]; // state++
506 throw;
507 } catch (...) {
508 state = BAD;
509 }
510 } catch (id e) {
511 state++;
512 [e check]; // state++;
513 }
514 testassert(state == 8);
515
516
517 testprintf("C++ try/catch, Objective-C exception subclass\n");
518
519 state = 0;
520 try {
521 state++;
522 try {
523 state++;
524 try {
525 state++;
526 @throw [Sub exception];
527 state = BAD;
528 } catch (...) {
529 state++;
530 throw;
531 state = BAD;
532 }
533 state = BAD;
534 } catch (void *e) {
535 state = BAD;
536 } catch (int e) {
537 state = BAD;
538 } catch (Super *e) {
539 state++;
540 [e check]; // state++
541 throw;
542 } catch (Sub *e) {
543 state = BAD;
544 } catch (...) {
545 state = BAD;
546 }
547 } catch (id e) {
548 state++;
549 [e check]; // state++;
550 }
551 testassert(state == 8);
552
553 #endif
554
555
556 #if !__OBJC2__ || TARGET_OS_EMBEDDED || TARGET_OS_IPHONE
557 // alt handlers for modern Mac OS only
558
559 #else
560 // alt handlers
561 // run a lot to catch failed unregistration (runtime complains at 1000)
562 #define ALT_HANDLER_REPEAT 2000
563 int i;
564
565 testprintf("alt handler, no exception\n");
566
567 for (i = 0; i < ALT_HANDLER_REPEAT; i++) {
568 PUSH_POOL {
569 state = 0;
570 @try {
571 state++;
572 @try {
573 uintptr_t token = objc_addExceptionHandler(altHandlerFail, 0);
574 state++;
575 objc_removeExceptionHandler(token);
576 }
577 @catch (...) {
578 state = BAD;
579 }
580 state++;
581 } @catch (...) {
582 state = BAD;
583 }
584 testassert(state == 3);
585 } POP_POOL;
586 }
587
588 testprintf("alt handler, exception thrown through\n");
589
590 for (i = 0; i < ALT_HANDLER_REPEAT; i++) {
591 PUSH_POOL {
592 state = 0;
593 @try {
594 state++;
595 @try {
596 state++;
597 uintptr_t token = objc_addExceptionHandler(altHandler2, (void*)altHandler2);
598 // state++ inside alt handler
599 @throw [Super exception];
600 state = BAD;
601 objc_removeExceptionHandler(token);
602 }
603 @catch (Sub *e) {
604 state = BAD;
605 }
606 state = BAD;
607 }
608 @catch (id e) {
609 testassert(state == 3);
610 state++;
611 [e check]; // state++
612 }
613 testassert(state == 5);
614 } POP_POOL;
615 }
616
617
618 testprintf("alt handler, nested\n");
619
620 for (i = 0; i < ALT_HANDLER_REPEAT; i++) {
621 PUSH_POOL {
622 state = 0;
623 @try {
624 state++;
625 @try {
626 state++;
627 // same-level handlers called in FIFO order (not stack-like)
628 uintptr_t token = objc_addExceptionHandler(altHandler4, (void*)altHandler4);
629 // state++ inside alt handler
630 uintptr_t token2 = objc_addExceptionHandler(altHandler5, (void*)altHandler5);
631 // state++ inside alt handler
632 throwWithAltHandler(); // state += 2 inside
633 state = BAD;
634 objc_removeExceptionHandler(token);
635 objc_removeExceptionHandler(token2);
636 }
637 @catch (id e) {
638 testassert(state == 6);
639 state++;
640 [e check]; // state++;
641 }
642 state++;
643 }
644 @catch (...) {
645 state = BAD;
646 }
647 testassert(state == 9);
648 } POP_POOL;
649 }
650
651
652 testprintf("alt handler, nested, rethrows in between\n");
653
654 for (i = 0; i < ALT_HANDLER_REPEAT; i++) {
655 PUSH_POOL {
656 state = 0;
657 @try {
658 state++;
659 @try {
660 state++;
661 // same-level handlers called in FIFO order (not stack-like)
662 uintptr_t token = objc_addExceptionHandler(altHandler5, (void*)altHandler5);
663 // state++ inside alt handler
664 uintptr_t token2 = objc_addExceptionHandler(altHandler6, (void*)altHandler6);
665 // state++ inside alt handler
666 throwWithAltHandlerAndRethrow(); // state += 3 inside
667 state = BAD;
668 objc_removeExceptionHandler(token);
669 objc_removeExceptionHandler(token2);
670 }
671 @catch (...) {
672 testassert(state == 7);
673 state++;
674 @throw;
675 }
676 state = BAD;
677 }
678 @catch (id e) {
679 testassert(state == 8);
680 state++;
681 [e check]; // state++
682 }
683 testassert(state == 10);
684 } POP_POOL;
685 }
686
687
688 testprintf("alt handler, exception thrown and caught inside\n");
689
690 for (i = 0; i < ALT_HANDLER_REPEAT; i++) {
691 PUSH_POOL {
692 state = 0;
693 @try {
694 state++;
695 uintptr_t token = objc_addExceptionHandler(altHandlerFail, 0);
696 @try {
697 state++;
698 @throw [Super exception];
699 state = BAD;
700 }
701 @catch (Super *e) {
702 state++;
703 [e check]; // state++
704 }
705 state++;
706 objc_removeExceptionHandler(token);
707 }
708 @catch (...) {
709 state = BAD;
710 }
711 testassert(state == 5);
712 } POP_POOL;
713 }
714
715
716 #if defined(USE_FOUNDATION)
717 testprintf("alt handler, rdar://10055775\n");
718
719 for (i = 0; i < ALT_HANDLER_REPEAT; i++) {
720 PUSH_POOL {
721 state = 0;
722 @try {
723 uintptr_t token = objc_addExceptionHandler(altHandler1, (void*)altHandler1);
724 {
725 id x = [NSArray array];
726 x = [NSArray array];
727 }
728 state++;
729 // state++ inside alt handler
730 [NSException raise:@"foo" format:@"bar"];
731 state = BAD;
732 objc_removeExceptionHandler(token);
733 } @catch (id e) {
734 testassert(state == 2);
735 }
736 } POP_POOL;
737 }
738 // defined(USE_FOUNDATION)
739 #endif
740
741
742 // alt handlers
743 #endif
744
745 } POP_POOL;
746
747 #if __cplusplus && __OBJC2__
748 std::set_terminate(terminator);
749 objc_terminate();
750 fail("should not have returned from objc_terminate()");
751 #else
752 succeed(FILENAME);
753 #endif
754 }
755