|
7 | 7 | #include <stddef.h> |
8 | 8 | #include <stdlib.h> |
9 | 9 | #include <sys/types.h> |
| 10 | +#include <csignal> |
10 | 11 |
|
11 | 12 | #include "platform/assert.h" |
12 | 13 | #include "platform/globals.h" |
| 14 | +#include "vm/os_thread.h" |
13 | 15 | #if defined(HOST_OS_WINDOWS) |
14 | 16 | #include <psapi.h> |
15 | 17 | #else |
16 | 18 | #include <unistd.h> |
17 | 19 | #endif |
18 | 20 |
|
| 21 | +#include <setjmp.h> |
| 22 | +#include <signal.h> |
19 | 23 | #include <iostream> |
20 | 24 | #include <limits> |
21 | 25 |
|
22 | 26 | #include "include/dart_api.h" |
23 | 27 |
|
24 | 28 | namespace dart { |
25 | 29 |
|
| 30 | +//////////////////////////////////////////////////////////////////////////////// |
| 31 | +// Tests for Dart -> native calls. |
| 32 | + |
26 | 33 | // Sums two ints and adds 42. |
27 | 34 | // Simple function to test trampolines. |
28 | 35 | // Also used for testing argument exception on passing null instead of a Dart |
@@ -449,7 +456,8 @@ DART_EXPORT float InventFloatValue() { |
449 | 456 | return retval; |
450 | 457 | } |
451 | 458 |
|
452 | | -// Functions for stress-testing GC by returning values that require boxing. |
| 459 | +//////////////////////////////////////////////////////////////////////////////// |
| 460 | +// Functions for stress-testing. |
453 | 461 |
|
454 | 462 | DART_EXPORT int64_t MinInt64() { |
455 | 463 | return 0x8000000000000000; |
@@ -511,4 +519,213 @@ DART_EXPORT int RedirectStderr() { |
511 | 519 | } |
512 | 520 | #endif |
513 | 521 |
|
| 522 | +//////////////////////////////////////////////////////////////////////////////// |
| 523 | +// Tests for callbacks. |
| 524 | + |
| 525 | +#define CHECK(X) \ |
| 526 | + if (!(X)) { \ |
| 527 | + fprintf(stderr, "%s\n", "Check failed: " #X); \ |
| 528 | + return 1; \ |
| 529 | + } |
| 530 | + |
| 531 | +#define CHECK_EQ(X, Y) CHECK((X) == (Y)) |
| 532 | + |
| 533 | +// Sanity test. |
| 534 | +DART_EXPORT int TestSimpleAddition(int (*add)(int, int)) { |
| 535 | + CHECK_EQ(add(10, 20), 30); |
| 536 | + return 0; |
| 537 | +} |
| 538 | + |
| 539 | +//// Following tests are copied from above, with the role of Dart and C++ code |
| 540 | +//// reversed. |
| 541 | + |
| 542 | +DART_EXPORT int TestIntComputation( |
| 543 | + int64_t (*fn)(int8_t, int16_t, int32_t, int64_t)) { |
| 544 | + CHECK_EQ(fn(125, 250, 500, 1000), 625); |
| 545 | + CHECK_EQ(0x7FFFFFFFFFFFFFFFLL, fn(0, 0, 0, 0x7FFFFFFFFFFFFFFFLL)); |
| 546 | + CHECK_EQ(((int64_t)-0x8000000000000000LL), |
| 547 | + fn(0, 0, 0, -0x8000000000000000LL)); |
| 548 | + return 0; |
| 549 | +} |
| 550 | + |
| 551 | +DART_EXPORT int TestUintComputation( |
| 552 | + uint64_t (*fn)(uint8_t, uint16_t, uint32_t, uint64_t)) { |
| 553 | + CHECK_EQ(0x7FFFFFFFFFFFFFFFLL, fn(0, 0, 0, 0x7FFFFFFFFFFFFFFFLL)); |
| 554 | + CHECK_EQ(-0x8000000000000000LL, fn(0, 0, 0, -0x8000000000000000LL)); |
| 555 | + CHECK_EQ(-1, (int64_t)fn(0, 0, 0, -1)); |
| 556 | + return 0; |
| 557 | +} |
| 558 | + |
| 559 | +DART_EXPORT int TestSimpleMultiply(double (*fn)(double)) { |
| 560 | + CHECK_EQ(fn(2.0), 2.0 * 1.337); |
| 561 | + return 0; |
| 562 | +} |
| 563 | + |
| 564 | +DART_EXPORT int TestSimpleMultiplyFloat(float (*fn)(float)) { |
| 565 | + CHECK(std::abs(fn(2.0) - 2.0 * 1.337) < 0.001); |
| 566 | + return 0; |
| 567 | +} |
| 568 | + |
| 569 | +DART_EXPORT int TestManyInts(intptr_t (*fn)(intptr_t, |
| 570 | + intptr_t, |
| 571 | + intptr_t, |
| 572 | + intptr_t, |
| 573 | + intptr_t, |
| 574 | + intptr_t, |
| 575 | + intptr_t, |
| 576 | + intptr_t, |
| 577 | + intptr_t, |
| 578 | + intptr_t)) { |
| 579 | + CHECK_EQ(55, fn(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); |
| 580 | + return 0; |
| 581 | +} |
| 582 | + |
| 583 | +DART_EXPORT int TestManyDoubles(double (*fn)(double, |
| 584 | + double, |
| 585 | + double, |
| 586 | + double, |
| 587 | + double, |
| 588 | + double, |
| 589 | + double, |
| 590 | + double, |
| 591 | + double, |
| 592 | + double)) { |
| 593 | + CHECK_EQ(55, fn(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); |
| 594 | + return 0; |
| 595 | +} |
| 596 | + |
| 597 | +DART_EXPORT int TestManyArgs(double (*fn)(intptr_t a, |
| 598 | + float b, |
| 599 | + intptr_t c, |
| 600 | + double d, |
| 601 | + intptr_t e, |
| 602 | + float f, |
| 603 | + intptr_t g, |
| 604 | + double h, |
| 605 | + intptr_t i, |
| 606 | + float j, |
| 607 | + intptr_t k, |
| 608 | + double l, |
| 609 | + intptr_t m, |
| 610 | + float n, |
| 611 | + intptr_t o, |
| 612 | + double p, |
| 613 | + intptr_t q, |
| 614 | + float r, |
| 615 | + intptr_t s, |
| 616 | + double t)) { |
| 617 | + CHECK(210.0 == fn(1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9, 10.0, 11, 12.0, 13, 14.0, |
| 618 | + 15, 16.0, 17, 18.0, 19, 20.0)); |
| 619 | + return 0; |
| 620 | +} |
| 621 | + |
| 622 | +DART_EXPORT int TestStore(int64_t* (*fn)(int64_t* a)) { |
| 623 | + int64_t p[2] = {42, 1000}; |
| 624 | + int64_t* result = fn(p); |
| 625 | + CHECK_EQ(*result, 1337); |
| 626 | + CHECK_EQ(p[1], 1337); |
| 627 | + CHECK_EQ(result, p + 1); |
| 628 | + return 0; |
| 629 | +} |
| 630 | + |
| 631 | +DART_EXPORT int TestReturnNull(int32_t fn()) { |
| 632 | + CHECK_EQ(fn(), 0); |
| 633 | + return 0; |
| 634 | +} |
| 635 | + |
| 636 | +DART_EXPORT int TestNullPointers(int64_t* (*fn)(int64_t* ptr)) { |
| 637 | + CHECK_EQ(fn(nullptr), nullptr); |
| 638 | + int64_t p[2] = {0}; |
| 639 | + CHECK_EQ(fn(p), p + 1); |
| 640 | + return 0; |
| 641 | +} |
| 642 | + |
| 643 | +struct CallbackTestData { |
| 644 | + int success; |
| 645 | + void (*callback)(); |
| 646 | +}; |
| 647 | + |
| 648 | +#if defined(TARGET_OS_LINUX) && !defined(PRODUCT) |
| 649 | + |
| 650 | +thread_local sigjmp_buf buf; |
| 651 | +void CallbackTestSignalHandler(int) { |
| 652 | + siglongjmp(buf, 1); |
| 653 | +} |
| 654 | + |
| 655 | +int ExpectAbort(void (*fn)()) { |
| 656 | + fprintf(stderr, "**** EXPECT STACKTRACE TO FOLLOW. THIS IS OK. ****\n"); |
| 657 | + |
| 658 | + struct sigaction old_action; |
| 659 | + int result = __sigsetjmp(buf, /*savesigs=*/1); |
| 660 | + if (result == 0) { |
| 661 | + // Install signal handler. |
| 662 | + struct sigaction handler; |
| 663 | + handler.sa_handler = CallbackTestSignalHandler; |
| 664 | + sigemptyset(&handler.sa_mask); |
| 665 | + handler.sa_flags = 0; |
| 666 | + |
| 667 | + sigaction(SIGABRT, &handler, &old_action); |
| 668 | + |
| 669 | + fn(); |
| 670 | + } else { |
| 671 | + // Caught the setjmp. |
| 672 | + sigaction(SIGABRT, &old_action, NULL); |
| 673 | + exit(0); |
| 674 | + } |
| 675 | + fprintf(stderr, "Expected abort!!!\n"); |
| 676 | + exit(1); |
| 677 | +} |
| 678 | + |
| 679 | +void* TestCallbackOnThreadOutsideIsolate(void* parameter) { |
| 680 | + CallbackTestData* data = reinterpret_cast<CallbackTestData*>(parameter); |
| 681 | + data->success = ExpectAbort(data->callback); |
| 682 | + return NULL; |
| 683 | +} |
| 684 | + |
| 685 | +int TestCallbackOtherThreadHelper(void* (*tester)(void*), void (*fn)()) { |
| 686 | + CallbackTestData data = {1, fn}; |
| 687 | + |
| 688 | + pthread_attr_t attr; |
| 689 | + int result = pthread_attr_init(&attr); |
| 690 | + CHECK_EQ(result, 0); |
| 691 | + |
| 692 | + pthread_t tid; |
| 693 | + result = pthread_create(&tid, &attr, tester, &data); |
| 694 | + CHECK_EQ(result, 0); |
| 695 | + |
| 696 | + result = pthread_attr_destroy(&attr); |
| 697 | + CHECK_EQ(result, 0); |
| 698 | + |
| 699 | + void* retval; |
| 700 | + result = pthread_join(tid, &retval); |
| 701 | + |
| 702 | + // Doesn't actually return because the other thread will exit when the test is |
| 703 | + // finished. |
| 704 | + UNREACHABLE(); |
| 705 | +} |
| 706 | + |
| 707 | +// Run a callback on another thread and verify that it triggers SIGABRT. |
| 708 | +DART_EXPORT int TestCallbackWrongThread(void (*fn)()) { |
| 709 | + return TestCallbackOtherThreadHelper(&TestCallbackOnThreadOutsideIsolate, fn); |
| 710 | +} |
| 711 | + |
| 712 | +// Verify that we get SIGABRT when invoking a native callback outside an |
| 713 | +// isolate. |
| 714 | +DART_EXPORT int TestCallbackOutsideIsolate(void (*fn)()) { |
| 715 | + Dart_Isolate current = Dart_CurrentIsolate(); |
| 716 | + |
| 717 | + Dart_ExitIsolate(); |
| 718 | + CallbackTestData data = {1, fn}; |
| 719 | + TestCallbackOnThreadOutsideIsolate(&data); |
| 720 | + Dart_EnterIsolate(current); |
| 721 | + |
| 722 | + return data.success; |
| 723 | +} |
| 724 | + |
| 725 | +DART_EXPORT int TestCallbackWrongIsolate(void (*fn)()) { |
| 726 | + return ExpectAbort(fn); |
| 727 | +} |
| 728 | + |
| 729 | +#endif // defined(TARGET_OS_LINUX) && !defined(PRODUCT) |
| 730 | + |
514 | 731 | } // namespace dart |
0 commit comments