aboutsummaryrefslogtreecommitdiff
path: root/src/lj_err.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lj_err.c')
-rw-r--r--src/lj_err.c399
1 files changed, 273 insertions, 126 deletions
diff --git a/src/lj_err.c b/src/lj_err.c
index ebc9ad12..b2e7f5f8 100644
--- a/src/lj_err.c
+++ b/src/lj_err.c
@@ -20,6 +20,63 @@
20#include "lj_trace.h" 20#include "lj_trace.h"
21#include "lj_vm.h" 21#include "lj_vm.h"
22 22
23/*
24** LuaJIT can either use internal or external frame unwinding:
25**
26** - Internal frame unwinding (INT) is free-standing and doesn't require
27** any OS or library support.
28**
29** - External frame unwinding (EXT) uses the system-provided unwind handler.
30**
31** Pros and Cons:
32**
33** - EXT requires unwind tables for *all* functions on the C stack between
34** the pcall/catch and the error/throw. This is the default on x64,
35** but needs to be manually enabled on x86 for non-C++ code.
36**
37** - INT is faster when actually throwing errors (but this happens rarely).
38** Setting up error handlers is zero-cost in any case.
39**
40** - EXT provides full interoperability with C++ exceptions. You can throw
41** Lua errors or C++ exceptions through a mix of Lua frames and C++ frames.
42** C++ destructors are called as needed. C++ exceptions caught by pcall
43** are converted to the string "C++ exception". Lua errors can be caught
44** with catch (...) in C++.
45**
46** - INT has only limited support for automatically catching C++ exceptions
47** on POSIX systems using DWARF2 stack unwinding. Other systems may use
48** the wrapper function feature. Lua errors thrown through C++ frames
49** cannot be caught by C++ code and C++ destructors are not run.
50**
51** INT is the default on x86 systems, EXT is the default on x64 systems.
52**
53** EXT can only be manually enabled on POSIX/x86 systems using DWARF2 stack
54** unwinding with -DLUAJIT_UNWIND_EXTERNAL. *All* C code must be compiled
55** with -funwind-tables (or -fexceptions). This includes LuaJIT itself (set
56** TARGET_CFLAGS), all of your C/Lua binding code, all loadable C modules
57** and all C libraries that have callbacks which may be used to call back
58** into Lua. C++ code must *not* be compiled with -fno-exceptions.
59**
60** EXT cannot be enabled on WIN32 since system exceptions use code-driven SEH.
61** EXT is mandatory on WIN64 since the calling convention has an abundance
62** of callee-saved registers (rbx, rbp, rsi, rdi, r12-r15, xmm6-xmm15).
63** EXT is mandatory on POSIX/x64 since the interpreter doesn't save r12/r13.
64*/
65
66#if defined(__ELF__) || defined(__MACH__)
67#if LJ_TARGET_X86
68#ifdef LUAJIT_UNWIND_EXTERNAL
69#define LJ_UNWIND_EXT 1
70#endif
71#elif LJ_TARGET_X64
72#define LJ_UNWIND_EXT 1
73#endif
74#elif defined(LUA_USE_WIN)
75#if LJ_TARGET_X64
76#define LJ_UNWIND_EXT 1
77#endif
78#endif
79
23/* -- Error messages ------------------------------------------------------ */ 80/* -- Error messages ------------------------------------------------------ */
24 81
25/* Error message strings. */ 82/* Error message strings. */
@@ -374,117 +431,249 @@ LUA_API int lua_getstack(lua_State *L, int level, lua_Debug *ar)
374 } 431 }
375} 432}
376 433
377/* -- Error handling ------------------------------------------------------ */ 434/* -- Internal frame unwinding -------------------------------------------- */
378
379/* Return string object for error message. */
380LJ_NOINLINE GCstr *lj_err_str(lua_State *L, ErrMsg em)
381{
382 return lj_str_newz(L, err2msg(em));
383}
384 435
385/* Unwind Lua stack and add error message on top. */ 436/* Unwind Lua stack and move error message to new top. */
386LJ_NOINLINE static void unwindstack(lua_State *L, TValue *top, int errcode) 437LJ_NOINLINE static void unwindstack(lua_State *L, TValue *top)
387{ 438{
388 lj_func_closeuv(L, top); 439 lj_func_closeuv(L, top);
389 switch (errcode) { 440 if (top < L->top-1) {
390 case LUA_ERRMEM: 441 copyTV(L, top, L->top-1);
391 setstrV(L, top, lj_err_str(L, LJ_ERR_ERRMEM)); 442 L->top = top+1;
392 break;
393 case LUA_ERRERR:
394 setstrV(L, top, lj_err_str(L, LJ_ERR_ERRERR));
395 break;
396 case LUA_ERRSYNTAX:
397 case LUA_ERRRUN:
398 copyTV(L, top, L->top - 1);
399 break;
400 default:
401 lua_assert(0);
402 break;
403 } 443 }
404 L->top = top+1;
405 lj_state_relimitstack(L); 444 lj_state_relimitstack(L);
406} 445}
407 446
408/* Throw error. Find catch frame, unwind stack and continue. */ 447/* Unwind until stop frame. Optionally cleanup frames. */
409LJ_NOINLINE void lj_err_throw(lua_State *L, int errcode) 448static void *err_unwind(lua_State *L, void *stopcf, int errcode)
410{ 449{
411 TValue *frame = L->base-1; 450 TValue *frame = L->base-1;
412 void *cf = L->cframe; 451 void *cf = L->cframe;
413 global_State *g = G(L);
414 if (L->status == LUA_ERRERR+1) { /* Don't touch the stack during lua_open. */
415 lj_vm_unwind_c(cf, errcode);
416 goto uncaught; /* unreachable */
417 }
418 lj_trace_abort(g);
419 setgcrefnull(g->jit_L);
420 L->status = 0;
421 while (cf) { 452 while (cf) {
422 if (cframe_nres(cframe_raw(cf)) < 0) { /* cframe without frame? */ 453 int32_t nres = cframe_nres(cframe_raw(cf));
423 TValue *top = restorestack(L, -cframe_nres(cf)); 454 if (nres < 0) { /* C frame without Lua frame? */
424 if (frame < top) { 455 TValue *top = restorestack(L, -nres);
425 L->cframe = cframe_prev(cf); 456 if (frame < top) { /* Frame reached? */
426 L->base = frame+1; 457 if (errcode) {
427 unwindstack(L, top, errcode); 458 L->cframe = cframe_prev(cf);
428 lj_vm_unwind_c(cf, errcode); 459 L->base = frame+1;
429 goto uncaught; /* unreachable */ 460 unwindstack(L, top);
461 }
462 return cf;
430 } 463 }
431 } 464 }
432 if (frame <= L->stack) 465 if (frame <= L->stack)
433 break; 466 break;
434 switch (frame_typep(frame)) { 467 switch (frame_typep(frame)) {
435 case FRAME_LUA: 468 case FRAME_LUA: /* Lua frame. */
436 case FRAME_LUAP: 469 case FRAME_LUAP:
437 frame = frame_prevl(frame); 470 frame = frame_prevl(frame);
438 break; 471 break;
439 case FRAME_C: 472 case FRAME_C: /* C frame. */
440 if (cframe_canyield(cf)) goto uncaught; 473#if LJ_UNWIND_EXT
474 if (errcode) {
475 L->cframe = cframe_prev(cf);
476 L->base = frame_prevd(frame) + 1;
477 unwindstack(L, frame);
478 } else if (cf != stopcf) {
479 cf = cframe_prev(cf);
480 frame = frame_prevd(frame);
481 break;
482 }
483 return NULL; /* Continue unwinding. */
484#else
485 UNUSED(stopcf);
441 cf = cframe_prev(cf); 486 cf = cframe_prev(cf);
442 /* fallthrough */
443 case FRAME_CONT:
444 case FRAME_VARG:
445 frame = frame_prevd(frame); 487 frame = frame_prevd(frame);
446 break; 488 break;
447 case FRAME_CP: 489#endif
448 L->cframe = cframe_prev(cf); 490 case FRAME_CP: /* Protected C frame. */
449 L->base = frame_prevd(frame) + 1; 491 if (cframe_canyield(cf)) { /* Resume? */
450 unwindstack(L, frame, errcode); 492 if (errcode) {
451 lj_vm_unwind_c(cf, errcode); 493 L->cframe = NULL;
452 goto uncaught; /* unreachable */ 494 L->status = cast_byte(errcode);
453 case FRAME_PCALL: 495 }
454 hook_leave(g); 496 return cframe_raw(cf);
497 }
498 if (errcode) {
499 L->cframe = cframe_prev(cf);
500 L->base = frame_prevd(frame) + 1;
501 unwindstack(L, frame);
502 }
503 return cf;
504 case FRAME_CONT: /* Continuation frame. */
505 case FRAME_VARG: /* Vararg frame. */
506 frame = frame_prevd(frame);
507 break;
508 case FRAME_PCALL: /* FF pcall() frame. */
509 if (errcode)
510 hook_leave(G(L));
455 /* fallthrough */ 511 /* fallthrough */
456 case FRAME_PCALLH: 512 case FRAME_PCALLH: /* FF pcall() frame inside hook. */
457 L->cframe = cf; 513 if (errcode) {
458 L->base = frame_prevd(frame) + 1; 514 L->cframe = cf;
459 unwindstack(L, L->base, errcode); 515 L->base = frame_prevd(frame) + 1;
460 lj_vm_unwind_ff(cf); 516 unwindstack(L, L->base);
461 goto uncaught; /* unreachable */ 517 return NULL; /* Call special handler. */
462 default: 518 }
463 lua_assert(0); 519 return cf;
464 goto uncaught;
465 } 520 }
466 } 521 }
467 /* No catch frame found. Must be a resume or an unprotected error. */ 522 /* No C frame. */
468uncaught: 523 if (errcode) {
469 L->status = cast_byte(errcode); 524 L->cframe = NULL;
470 L->cframe = NULL; 525 L->base = L->stack+1;
471 if (cframe_canyield(cf)) { /* Resume? */ 526 unwindstack(L, L->base);
472 unwindstack(L, L->top, errcode); 527 if (G(L)->panic)
473 lj_vm_unwind_c(cframe_raw(cf), errcode); 528 G(L)->panic(L);
529 exit(EXIT_FAILURE);
474 } 530 }
475 /* Better rethrow on main thread than panic. */ 531 return L; /* Anything not-NULL will do. */
476 { 532}
477 if (L != mainthread(g)) 533
478 lj_err_throw(mainthread(g), errcode); 534/* -- External frame unwinding -------------------------------------------- */
479 if (g->panic) { 535
480 L->base = L->stack+1; 536#if defined(__ELF__) || defined(__MACH__)
481 unwindstack(L, L->base, errcode); 537
482 g->panic(L); 538#include <unwind.h>
539
540#define LJ_UEXCLASS 0x4c55414a49543200ULL /* LUAJIT2\0 */
541#define LJ_UEXCLASS_MAKE(c) (LJ_UEXCLASS | (_Unwind_Exception_Class)(c))
542#define LJ_UEXCLASS_CHECK(cl) (((cl) ^ LJ_UEXCLASS) <= 0xff)
543#define LJ_UEXCLASS_ERRCODE(cl) (cast_int((cl) & 0xff))
544
545/* DWARF2 personality handler referenced from interpreter .eh_frame. */
546LJ_FUNCA int lj_err_unwind_dwarf(int version, _Unwind_Action actions,
547 _Unwind_Exception_Class uexclass, struct _Unwind_Exception *uex,
548 struct _Unwind_Context *ctx)
549{
550 void *cf;
551 lua_State *L;
552 if (version != 1)
553 return _URC_FATAL_PHASE1_ERROR;
554 UNUSED(uexclass);
555 cf = (void *)_Unwind_GetCFA(ctx);
556 L = cframe_L(cf);
557 if ((actions & _UA_SEARCH_PHASE)) {
558#if LJ_UNWIND_EXT
559 if (err_unwind(L, cf, 0) == NULL)
560 return _URC_CONTINUE_UNWIND;
561#endif
562 if (!LJ_UEXCLASS_CHECK(uexclass)) {
563 setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRCPP));
564 }
565 return _URC_HANDLER_FOUND;
566 }
567 if ((actions & _UA_CLEANUP_PHASE)) {
568 int errcode;
569 if (LJ_UEXCLASS_CHECK(uexclass)) {
570 errcode = LJ_UEXCLASS_ERRCODE(uexclass);
571 } else {
572 if ((actions & _UA_HANDLER_FRAME))
573 _Unwind_DeleteException(uex);
574 errcode = LUA_ERRRUN;
575 }
576#if LJ_UNWIND_EXT
577 if (err_unwind(L, cf, errcode)) {
578 _Unwind_SetGR(ctx, 0, errcode);
579 _Unwind_SetIP(ctx, (_Unwind_Ptr)lj_vm_unwind_c_eh);
580 return _URC_INSTALL_CONTEXT;
581 } else if ((actions & _UA_HANDLER_FRAME)) {
582 _Unwind_SetIP(ctx, (_Unwind_Ptr)lj_vm_unwind_ff_eh);
583 return _URC_INSTALL_CONTEXT;
483 } 584 }
585#else
586 /* This is not the proper way to escape from the unwinder. We get away
587 ** with it on x86 because the interpreter restores all callee-saved regs.
588 */
589 lj_err_throw(L, errcode);
590#endif
591 }
592 return _URC_CONTINUE_UNWIND;
593}
594
595#if LJ_UNWIND_EXT
596/* NYI: this is not thread-safe. */
597static struct _Unwind_Exception static_uex;
598
599/* Raise DWARF2 exception. */
600static void err_raise_ext(int errcode)
601{
602 static_uex.exception_class = LJ_UEXCLASS_MAKE(errcode);
603 static_uex.exception_cleanup = NULL;
604 _Unwind_RaiseException(&static_uex);
605}
606#endif
607
608#elif defined(_WIN64)
609
610#define WIN32_LEAN_AND_MEAN
611#include <windows.h>
612
613#define LJ_EXCODE ((DWORD)0x024c4a00)
614#define LJ_EXCODE_MAKE(c) (LJ_EXCODE | (DWORD)(c))
615#define LJ_EXCODE_CHECK(cl) (((cl) ^ LJ_EXCODE) <= 0xff)
616#define LJ_EXCODE_ERRCODE(cl) (cast_int((cl) & 0xff))
617
618/* NYI: Win64 exception handler for interpreter frame. */
619
620/* Raise Windows exception. */
621static void err_raise_ext(int errcode)
622{
623 RaiseException(LJ_EXCODE_MAKE(errcode), 0, 0, NULL);
624}
625
626#endif
627
628/* -- Error handling ------------------------------------------------------ */
629
630/* Throw error. Find catch frame, unwind stack and continue. */
631LJ_NOINLINE void lj_err_throw(lua_State *L, int errcode)
632{
633 global_State *g = G(L);
634 lj_trace_abort(g);
635 setgcrefnull(g->jit_L);
636 L->status = 0;
637#if LJ_UNWIND_EXT
638 err_raise_ext(errcode);
639 /*
640 ** A return from this function signals a corrupt C stack that cannot be
641 ** unwound. We have no choice but to call the panic function and exit.
642 **
643 ** Usually this is caused by a C function without unwind information.
644 ** This should never happen on x64, but may happen on x86 if you've
645 ** manually enabled LUAJIT_UNWIND_EXTERNAL and forgot to recompile *every*
646 ** non-C++ file with -funwind-tables.
647 */
648 if (G(L)->panic)
649 G(L)->panic(L);
650#else
651 {
652 void *cf = err_unwind(L, NULL, errcode);
653 if (cf)
654 lj_vm_unwind_c(cf, errcode);
655 else
656 lj_vm_unwind_ff(cframe_raw(L->cframe));
484 } 657 }
658#endif
485 exit(EXIT_FAILURE); 659 exit(EXIT_FAILURE);
486} 660}
487 661
662/* Return string object for error message. */
663LJ_NOINLINE GCstr *lj_err_str(lua_State *L, ErrMsg em)
664{
665 return lj_str_newz(L, err2msg(em));
666}
667
668/* Out-of-memory error. */
669LJ_NOINLINE void lj_err_mem(lua_State *L)
670{
671 if (L->status == LUA_ERRERR+1) /* Don't touch the stack during lua_open. */
672 lj_vm_unwind_c(L->cframe, LUA_ERRMEM);
673 setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRMEM));
674 lj_err_throw(L, LUA_ERRMEM);
675}
676
488/* Find error function for runtime errors. Requires an extra stack traversal. */ 677/* Find error function for runtime errors. Requires an extra stack traversal. */
489static ptrdiff_t finderrfunc(lua_State *L) 678static ptrdiff_t finderrfunc(lua_State *L)
490{ 679{
@@ -507,7 +696,6 @@ static ptrdiff_t finderrfunc(lua_State *L)
507 frame = frame_prevl(frame); 696 frame = frame_prevl(frame);
508 break; 697 break;
509 case FRAME_C: 698 case FRAME_C:
510 if (cframe_canyield(cf)) return 0;
511 cf = cframe_prev(cf); 699 cf = cframe_prev(cf);
512 /* fallthrough */ 700 /* fallthrough */
513 case FRAME_CONT: 701 case FRAME_CONT:
@@ -515,6 +703,7 @@ static ptrdiff_t finderrfunc(lua_State *L)
515 frame = frame_prevd(frame); 703 frame = frame_prevd(frame);
516 break; 704 break;
517 case FRAME_CP: 705 case FRAME_CP:
706 if (cframe_canyield(cf)) return 0;
518 if (cframe_errfunc(cf) >= 0) 707 if (cframe_errfunc(cf) >= 0)
519 return cframe_errfunc(cf); 708 return cframe_errfunc(cf);
520 frame = frame_prevd(frame); 709 frame = frame_prevd(frame);
@@ -540,8 +729,10 @@ LJ_NOINLINE void lj_err_run(lua_State *L)
540 TValue *errfunc = restorestack(L, ef); 729 TValue *errfunc = restorestack(L, ef);
541 TValue *top = L->top; 730 TValue *top = L->top;
542 lj_trace_abort(G(L)); 731 lj_trace_abort(G(L));
543 if (!tvisfunc(errfunc) || L->status == LUA_ERRERR) 732 if (!tvisfunc(errfunc) || L->status == LUA_ERRERR) {
733 setstrV(L, top-1, lj_err_str(L, LJ_ERR_ERRERR));
544 lj_err_throw(L, LUA_ERRERR); 734 lj_err_throw(L, LUA_ERRERR);
735 }
545 L->status = LUA_ERRERR; 736 L->status = LUA_ERRERR;
546 copyTV(L, top, top-1); 737 copyTV(L, top, top-1);
547 copyTV(L, top-1, errfunc); 738 copyTV(L, top-1, errfunc);
@@ -763,47 +954,3 @@ LUALIB_API int luaL_error(lua_State *L, const char *fmt, ...)
763 return 0; /* unreachable */ 954 return 0; /* unreachable */
764} 955}
765 956
766/* -- C++ exception support ----------------------------------------------- */
767
768#if defined(__ELF__) || defined(__MACH__)
769typedef enum
770{
771 _URC_NO_REASON,
772 _URC_FOREIGN_EXCEPTION_CAUGHT,
773 _URC_FATAL_PHASE2_ERROR,
774 _URC_FATAL_PHASE1_ERROR,
775 _URC_NORMAL_STOP,
776 _URC_END_OF_STACK,
777 _URC_HANDLER_FOUND,
778 _URC_INSTALL_CONTEXT,
779 _URC_CONTINUE_UNWIND
780} _Unwind_Reason_Code;
781
782#define _UA_SEARCH_PHASE 1
783#define _UA_CLEANUP_PHASE 2
784#define _UA_HANDLER_FRAME 4
785#define _UA_FORCE_UNWIND 8
786#define _UA_END_OF_STACK 16
787
788extern void *_Unwind_GetCFA(void *ctx);
789extern void _Unwind_DeleteException(void *uex);
790
791/* DWARF2 personality handler referenced from .eh_frame. */
792LJ_FUNCA int lj_err_unwind_dwarf(int version, int actions, uint64_t uexclass,
793 void *uex, void *ctx)
794{
795 if (version != 1)
796 return _URC_FATAL_PHASE1_ERROR;
797 UNUSED(uexclass);
798 if ((actions & _UA_SEARCH_PHASE))
799 return _URC_HANDLER_FOUND;
800 if ((actions & _UA_HANDLER_FRAME)) {
801 void *cf = _Unwind_GetCFA(ctx);
802 lua_State *L = cframe_L(cf);
803 _Unwind_DeleteException(uex);
804 lj_err_msg(L, LJ_ERR_ERRCPP);
805 }
806 return _URC_CONTINUE_UNWIND;
807}
808#endif
809