exc.m 22 KB

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