diff options
Diffstat (limited to 'src/lj_err.c')
-rw-r--r-- | src/lj_err.c | 98 |
1 files changed, 83 insertions, 15 deletions
diff --git a/src/lj_err.c b/src/lj_err.c index b2e7f5f8..b8070250 100644 --- a/src/lj_err.c +++ b/src/lj_err.c | |||
@@ -493,7 +493,7 @@ static void *err_unwind(lua_State *L, void *stopcf, int errcode) | |||
493 | L->cframe = NULL; | 493 | L->cframe = NULL; |
494 | L->status = cast_byte(errcode); | 494 | L->status = cast_byte(errcode); |
495 | } | 495 | } |
496 | return cframe_raw(cf); | 496 | return cf; |
497 | } | 497 | } |
498 | if (errcode) { | 498 | if (errcode) { |
499 | L->cframe = cframe_prev(cf); | 499 | L->cframe = cframe_prev(cf); |
@@ -514,9 +514,8 @@ static void *err_unwind(lua_State *L, void *stopcf, int errcode) | |||
514 | L->cframe = cf; | 514 | L->cframe = cf; |
515 | L->base = frame_prevd(frame) + 1; | 515 | L->base = frame_prevd(frame) + 1; |
516 | unwindstack(L, L->base); | 516 | unwindstack(L, L->base); |
517 | return NULL; /* Call special handler. */ | ||
518 | } | 517 | } |
519 | return cf; | 518 | return (void *)((intptr_t)cf | CFRAME_UNWIND_FF); |
520 | } | 519 | } |
521 | } | 520 | } |
522 | /* No C frame. */ | 521 | /* No C frame. */ |
@@ -528,7 +527,7 @@ static void *err_unwind(lua_State *L, void *stopcf, int errcode) | |||
528 | G(L)->panic(L); | 527 | G(L)->panic(L); |
529 | exit(EXIT_FAILURE); | 528 | exit(EXIT_FAILURE); |
530 | } | 529 | } |
531 | return L; /* Anything not-NULL will do. */ | 530 | return L; /* Anything non-NULL will do. */ |
532 | } | 531 | } |
533 | 532 | ||
534 | /* -- External frame unwinding -------------------------------------------- */ | 533 | /* -- External frame unwinding -------------------------------------------- */ |
@@ -574,12 +573,12 @@ LJ_FUNCA int lj_err_unwind_dwarf(int version, _Unwind_Action actions, | |||
574 | errcode = LUA_ERRRUN; | 573 | errcode = LUA_ERRRUN; |
575 | } | 574 | } |
576 | #if LJ_UNWIND_EXT | 575 | #if LJ_UNWIND_EXT |
577 | if (err_unwind(L, cf, errcode)) { | 576 | cf = err_unwind(L, cf, errcode); |
577 | if (cf) { | ||
578 | _Unwind_SetGR(ctx, 0, errcode); | 578 | _Unwind_SetGR(ctx, 0, errcode); |
579 | _Unwind_SetIP(ctx, (_Unwind_Ptr)lj_vm_unwind_c_eh); | 579 | _Unwind_SetIP(ctx, (_Unwind_Ptr)(cframe_unwind_ff(cf) ? |
580 | return _URC_INSTALL_CONTEXT; | 580 | lj_vm_unwind_ff_eh : |
581 | } else if ((actions & _UA_HANDLER_FRAME)) { | 581 | lj_vm_unwind_c_eh)); |
582 | _Unwind_SetIP(ctx, (_Unwind_Ptr)lj_vm_unwind_ff_eh); | ||
583 | return _URC_INSTALL_CONTEXT; | 582 | return _URC_INSTALL_CONTEXT; |
584 | } | 583 | } |
585 | #else | 584 | #else |
@@ -607,20 +606,89 @@ static void err_raise_ext(int errcode) | |||
607 | 606 | ||
608 | #elif defined(_WIN64) | 607 | #elif defined(_WIN64) |
609 | 608 | ||
609 | /* | ||
610 | ** Someone in Redmond owes me several days of my life. A lot of this is | ||
611 | ** undocumented or just plain wrong on MSDN. Some of it can be gathered | ||
612 | ** from 3rd party docs or must be found by trial-and-error. They really | ||
613 | ** don't want you to write your own language-specific exception handler | ||
614 | ** or to interact gracefully with MSVC. :-( | ||
615 | ** | ||
616 | ** Apparently MSVC doesn't call C++ destructors for foreign exceptions | ||
617 | ** unless you compile your C++ code with /EHa. Unfortunately this means | ||
618 | ** catch (...) also catches things like access violations. The use of | ||
619 | ** _set_se_translator doesn't really help, because it requires /EHa, too. | ||
620 | */ | ||
621 | |||
610 | #define WIN32_LEAN_AND_MEAN | 622 | #define WIN32_LEAN_AND_MEAN |
611 | #include <windows.h> | 623 | #include <windows.h> |
612 | 624 | ||
613 | #define LJ_EXCODE ((DWORD)0x024c4a00) | 625 | /* Taken from: http://www.nynaeve.net/?p=99 */ |
626 | typedef struct UndocumentedDispatcherContext { | ||
627 | ULONG64 ControlPc; | ||
628 | ULONG64 ImageBase; | ||
629 | PRUNTIME_FUNCTION FunctionEntry; | ||
630 | ULONG64 EstablisherFrame; | ||
631 | ULONG64 TargetIp; | ||
632 | PCONTEXT ContextRecord; | ||
633 | PEXCEPTION_ROUTINE LanguageHandler; | ||
634 | PVOID HandlerData; | ||
635 | PUNWIND_HISTORY_TABLE HistoryTable; | ||
636 | ULONG ScopeIndex; | ||
637 | ULONG Fill0; | ||
638 | } UndocumentedDispatcherContext; | ||
639 | |||
640 | #ifdef _MSC_VER | ||
641 | /* Another wild guess. */ | ||
642 | extern __DestructExceptionObject(EXCEPTION_RECORD *rec, int nothrow); | ||
643 | #endif | ||
644 | |||
645 | #define LJ_MSVC_EXCODE ((DWORD)0xe06d7363) | ||
646 | |||
647 | #define LJ_EXCODE ((DWORD)0xe24c4a00) | ||
614 | #define LJ_EXCODE_MAKE(c) (LJ_EXCODE | (DWORD)(c)) | 648 | #define LJ_EXCODE_MAKE(c) (LJ_EXCODE | (DWORD)(c)) |
615 | #define LJ_EXCODE_CHECK(cl) (((cl) ^ LJ_EXCODE) <= 0xff) | 649 | #define LJ_EXCODE_CHECK(cl) (((cl) ^ LJ_EXCODE) <= 0xff) |
616 | #define LJ_EXCODE_ERRCODE(cl) (cast_int((cl) & 0xff)) | 650 | #define LJ_EXCODE_ERRCODE(cl) (cast_int((cl) & 0xff)) |
617 | 651 | ||
618 | /* NYI: Win64 exception handler for interpreter frame. */ | 652 | /* Win64 exception handler for interpreter frame. */ |
653 | LJ_FUNCA EXCEPTION_DISPOSITION lj_err_unwind_win64(EXCEPTION_RECORD *rec, | ||
654 | void *cf, CONTEXT *ctx, UndocumentedDispatcherContext *dispatch) | ||
655 | { | ||
656 | lua_State *L = cframe_L(cf); | ||
657 | if ((rec->ExceptionFlags & 6)) { /* EH_UNWINDING|EH_EXIT_UNWIND */ | ||
658 | err_unwind(L, cf, 1); /* Unwind internal frames. */ | ||
659 | } else { | ||
660 | void *cf2 = err_unwind(L, cf, 0); | ||
661 | if (cf2) { /* We catch it, so start unwinding the upper frames. */ | ||
662 | int errcode; | ||
663 | if (LJ_EXCODE_CHECK(rec->ExceptionCode)) { | ||
664 | errcode = LJ_EXCODE_ERRCODE(rec->ExceptionCode); | ||
665 | } else if (rec->ExceptionCode == LJ_MSVC_EXCODE) { | ||
666 | #ifdef _MSC_VER | ||
667 | __DestructExceptionObject(rec, 1); | ||
668 | #endif | ||
669 | setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRCPP)); | ||
670 | errcode = LUA_ERRRUN; | ||
671 | } else { /* Don't catch access violations etc. */ | ||
672 | return ExceptionContinueSearch; | ||
673 | } | ||
674 | /* Unwind the stack and call all handlers for all lower C frames | ||
675 | ** (including ourselves) again with EH_UNWINDING set. Then set | ||
676 | ** rsp = cf, rax = errcode and jump to the specified target. | ||
677 | */ | ||
678 | RtlUnwindEx(cf, (void *)(cframe_unwind_ff(cf2) ? | ||
679 | lj_vm_unwind_ff_eh : | ||
680 | lj_vm_unwind_c_eh), | ||
681 | rec, (void *)errcode, ctx, dispatch->HistoryTable); | ||
682 | /* RtlUnwindEx should never return. */ | ||
683 | } | ||
684 | } | ||
685 | return ExceptionContinueSearch; | ||
686 | } | ||
619 | 687 | ||
620 | /* Raise Windows exception. */ | 688 | /* Raise Windows exception. */ |
621 | static void err_raise_ext(int errcode) | 689 | static void err_raise_ext(int errcode) |
622 | { | 690 | { |
623 | RaiseException(LJ_EXCODE_MAKE(errcode), 0, 0, NULL); | 691 | RaiseException(LJ_EXCODE_MAKE(errcode), 1 /* EH_NONCONTINUABLE */, 0, NULL); |
624 | } | 692 | } |
625 | 693 | ||
626 | #endif | 694 | #endif |
@@ -650,10 +718,10 @@ LJ_NOINLINE void lj_err_throw(lua_State *L, int errcode) | |||
650 | #else | 718 | #else |
651 | { | 719 | { |
652 | void *cf = err_unwind(L, NULL, errcode); | 720 | void *cf = err_unwind(L, NULL, errcode); |
653 | if (cf) | 721 | if (cframe_unwind_ff(cf)) |
654 | lj_vm_unwind_c(cf, errcode); | 722 | lj_vm_unwind_ff(cframe_raw(cf)); |
655 | else | 723 | else |
656 | lj_vm_unwind_ff(cframe_raw(L->cframe)); | 724 | lj_vm_unwind_c(cframe_raw(cf), errcode); |
657 | } | 725 | } |
658 | #endif | 726 | #endif |
659 | exit(EXIT_FAILURE); | 727 | exit(EXIT_FAILURE); |