From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from [87.239.111.99] (localhost [127.0.0.1]) by dev.tarantool.org (Postfix) with ESMTP id 007546FCB1; Thu, 6 Oct 2022 12:49:26 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 007546FCB1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1665049767; bh=7kBvOAiDo2JW7OfiapLDhXvgqEXywjpGGwu35SXXkaM=; h=To:Cc:Date:In-Reply-To:References:Subject:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=g6NNk/mezrKktVA5lBovoE5JYkGIDPweJ2ZnM8MqnbEZyxa62jRZhih+ukiRNkfrq yLHoJB5vTA8afHKo4R1rYcJtAG/fD0XSiW/N4v2GbgHyukNuHsWosJFnAbVc8n4cev 4X+iDtiCYpIlpre2ko6Bw4kPriw6DtLycjce6YqU= Received: from mail-lj1-f174.google.com (mail-lj1-f174.google.com [209.85.208.174]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id 178106FCB1 for ; Thu, 6 Oct 2022 12:48:57 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 178106FCB1 Received: by mail-lj1-f174.google.com with SMTP id a12so1586285ljr.7 for ; Thu, 06 Oct 2022 02:48:57 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date; bh=tQpZaUo4GOSAkmWjcvffKQcGOAuVns0VbPMRkWbPBZU=; b=w7ApACbIU4AFqxxKyjeshpWlNWW703d7C87D3FI3nz+vFsgIfFWSdBU6A8I3Q4/gpn TGuqlWrhY0r2Vyupvkixf4wIwqAi3fHlQQX/1h/ADkcS4NdKRcVcz+BTkICj2bMiUsqJ 7AzROyoMTE3mgofRKSWr2m3SbkF2UyYHOdaaY4lJEWFa8cemWKiyox8d/4kH1CTYg/V2 ubmAfwMN/2amrtATuXVFMPU+xMJZfsXeg03Y1w2osh3h7NTYMuRRTiBaqZ/PGMJ9bX7U 7njWco2+3wxXB7UmoHCyBuw+V0IC8ho3Fw+JKhgIB7NgVDZPX2oS7JFfu93iz8GiaSkg XLBA== X-Gm-Message-State: ACrzQf0/ec7WRpJ9X9bUJksres2t4ubFVlAaWBGXH9MCGcWW0ghDhKmQ a/rx0zgyZmDYah4fwNJB/GHAz4GRknTHOnETPEs= X-Google-Smtp-Source: AMsMyM6odNyMEN3ydLKM5Z5aPNVK/SFG/JtshcvKsnOhgypQ/Ybpsnk+QpC3WBU9tKx6uX+/IO+x3Q== X-Received: by 2002:a2e:808a:0:b0:26d:cced:beb1 with SMTP id i10-20020a2e808a000000b0026dccedbeb1mr1488305ljg.299.1665049735883; Thu, 06 Oct 2022 02:48:55 -0700 (PDT) Received: from localhost.localdomain (128-69-252-100.broadband.corbina.ru. [128.69.252.100]) by smtp.gmail.com with ESMTPSA id o20-20020a056512231400b004979ec19380sm2628676lfu.285.2022.10.06.02.48.55 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Thu, 06 Oct 2022 02:48:55 -0700 (PDT) To: tarantool-patches@dev.tarantool.org, sergos@tarantool.org, skaplun@tarantool.org Cc: Maksim Kokryashkin Date: Thu, 6 Oct 2022 12:48:44 +0300 Message-Id: <20221006094849.85442-2-max.kokryashkin@gmail.com> X-Mailer: git-send-email 2.32.1 (Apple Git-133) In-Reply-To: <20221006094849.85442-1-max.kokryashkin@gmail.com> References: <20221006094849.85442-1-max.kokryashkin@gmail.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Subject: [Tarantool-patches] [PATCH luajit v2 1/6] Cleanup and enable external unwinding for more platforms. X-BeenThere: tarantool-patches@dev.tarantool.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Maksim Kokryashkin via Tarantool-patches Reply-To: Maksim Kokryashkin Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" (cherry picked from commit e131936133c58de4426c595db2341caf5a1665b5) This commit enables external unwinding on all platforms, that create unwind tables by default. Corresponding check is added to the build routine. Also, GC64 mode is now enabled on MacOS by default, as non-GC64 mode is forbidden. Maxim Kokryashkin: * added the description for the patch Needed for tarantool/tarantool#6096 Part of tarantool/tarantool#7230 --- >> +if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") >> + set(LUAJIT_ENABLE_GC64 ON) >> +endif() >Also, I see no fortified enabled in the LuaJIT original commit. Is this >because this commit is later than enabling GC64 mode by default? Yes, exactly. >> + execute_process( >> + COMMAND bash -c "exec 2>/dev/null; echo 'extern void b(void);int a(void){b();return 0;}' | ${CMAKE_C_COMPILER} -c -x c - -o tmpunwind.o && grep -qa -e eh_frame -e __unwind_info tmpunwind.o && echo E; rm -f tmpunwind.o" > >Side note: I'm OK with the same check as Mike did. >Does `check_c_compiler_flag(-funwind-tables TESTUNWIND)` check the same >thing, but in a more readable way? No, because it only checks that the flag is supported, but it doesn’t check whether it is enabled by default. In our case, it is vital to know that compiler enables that option automatically for us. .github/workflows/macos-x86_64.yml | 20 +- CMakeLists.txt | 3 + cmake/SetTargetFlags.cmake | 22 +- doc/extensions.html | 22 +- src/Makefile.original | 11 +- src/lj_arch.h | 27 ++- src/lj_err.c | 321 +++++++++++++++-------------- 7 files changed, 214 insertions(+), 212 deletions(-) diff --git a/.github/workflows/macos-x86_64.yml b/.github/workflows/macos-x86_64.yml index 840806e3..dafd1796 100644 --- a/.github/workflows/macos-x86_64.yml +++ b/.github/workflows/macos-x86_64.yml @@ -35,7 +35,7 @@ jobs: fail-fast: false matrix: BUILDTYPE: [Debug, Release] - GC64: [ON, OFF] + GC64: ON include: - BUILDTYPE: Debug CMAKEFLAGS: -DCMAKE_BUILD_TYPE=Debug -DLUA_USE_ASSERT=ON -DLUA_USE_APICHECK=ON @@ -69,15 +69,6 @@ jobs: - name: test run: cmake --build . --parallel --target test - test-tarantool-debug-wo-GC64: - name: Tarantool Debug GC64:OFF - needs: test-luajit - uses: tarantool/tarantool/.github/workflows/luajit-integration.yml@master - with: - GC64: OFF - buildtype: Debug - host: macos-11 - revision: ${{ github.sha }} test-tarantool-debug-w-GC64: name: Tarantool Debug GC64:ON needs: test-luajit @@ -87,15 +78,6 @@ jobs: buildtype: Debug host: macos-11 revision: ${{ github.sha }} - test-tarantool-release-wo-GC64: - name: Tarantool Release GC64:OFF - needs: test-luajit - uses: tarantool/tarantool/.github/workflows/luajit-integration.yml@master - with: - GC64: OFF - buildtype: RelWithDebInfo - host: macos-11 - revision: ${{ github.sha }} test-tarantool-release-w-GC64: name: Tarantool Release GC64:ON needs: test-luajit diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b49f9d7..c4f3ef62 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -176,6 +176,9 @@ endif() # Enable GC64 mode for x64. option(LUAJIT_ENABLE_GC64 "GC64 mode for x64" OFF) +if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + set(LUAJIT_ENABLE_GC64 ON) +endif() if(LUAJIT_ENABLE_GC64) AppendFlags(TARGET_C_FLAGS -DLUAJIT_ENABLE_GC64) endif() diff --git a/cmake/SetTargetFlags.cmake b/cmake/SetTargetFlags.cmake index b544d2ac..36896aff 100644 --- a/cmake/SetTargetFlags.cmake +++ b/cmake/SetTargetFlags.cmake @@ -15,6 +15,22 @@ endif() LuaJITTestArch(TESTARCH "${TARGET_C_FLAGS}") LuaJITArch(LUAJIT_ARCH "${TESTARCH}") +string(FIND ${TARGET_C_FLAGS} "LJ_NO_UNWIND 1" UNWIND_POS) +if(UNWIND_POS EQUAL -1) + execute_process( + COMMAND bash -c "exec 2>/dev/null; echo 'extern void b(void);int a(void){b();return 0;}' | ${CMAKE_C_COMPILER} -c -x c - -o tmpunwind.o && grep -qa -e eh_frame -e __unwind_info tmpunwind.o && echo E; rm -f tmpunwind.o" + WORKING_DIRECTORY ${LUAJIT_SOURCE_DIR} + OUTPUT_VARIABLE TESTUNWIND + RESULT_VARIABLE TESTUNWIND_RC + ) + if(TESTUNWIND_RC EQUAL 0) + string(FIND "${TESTUNWIND}" "E" UNW_TEST_POS) + if(NOT UNW_TEST_POS EQUAL -1) + AppendFlags(TARGET_C_FLAGS -DLUAJIT_UNWIND_EXTERNAL) + endif() + endif() +endif() + # Target-specific compiler options. # # x86/x64 only: For GCC 4.2 or higher and if you don't intend to @@ -25,12 +41,6 @@ if(LUAJIT_ARCH STREQUAL "x86") endif() if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") - if(LUAJIT_ARCH STREQUAL "x64") - # XXX: Set -pagezero_size to hint when allocating 32 - # bit memory on OSX/x64, otherwise the lower 4GB are blocked. - AppendFlags(TARGET_BIN_FLAGS -pagezero_size 10000 -image_base 100000000) - AppendFlags(TARGET_SHARED_FLAGS -image_base 7fff04c4a000) - endif() AppendFlags(TARGET_SHARED_FLAGS -single_module -undefined dynamic_lookup) else() # Linux and FreeBSD. AppendFlags(TARGET_BIN_FLAGS -Wl,-E) diff --git a/doc/extensions.html b/doc/extensions.html index e0f136e2..777e9928 100644 --- a/doc/extensions.html +++ b/doc/extensions.html @@ -395,29 +395,19 @@ the toolchain used to compile LuaJIT: Interoperability -POSIX/x64, DWARF2 unwinding -GCC 4.3+, Clang +External frame unwinding +GCC, Clang, MSVC Full -ARM -DLUAJIT_UNWIND_EXTERNAL -GCC, Clang -Full - - -Other platforms, DWARF2 unwinding +Internal frame unwinding + DWARF2 GCC, Clang Limited - -Windows/x64 -MSVC or WinSDK -Full - -Windows/x86 -Any -Full +Windows 64 bit +non-MSVC +Limited Other platforms diff --git a/src/Makefile.original b/src/Makefile.original index dd1c6a76..c9609700 100644 --- a/src/Makefile.original +++ b/src/Makefile.original @@ -320,6 +320,13 @@ else ifeq (,$(shell $(TARGET_CC) -o /dev/null -c -x c /dev/null -fno-stack-protector 2>/dev/null || echo 1)) TARGET_XCFLAGS+= -fno-stack-protector endif +ifeq (,$(findstring LJ_NO_UNWIND 1,$(TARGET_TESTARCH))) + # Find out whether the target toolchain always generates unwind tables. + TARGET_TESTUNWIND=$(shell exec 2>/dev/null; echo 'extern void b(void);int a(void){b();return 0;}' | $(TARGET_CC) -c -x c - -o tmpunwind.o && grep -qa -e eh_frame -e __unwind_info tmpunwind.o && echo E; rm -f tmpunwind.o) + ifneq (,$(findstring E,$(TARGET_TESTUNWIND))) + TARGET_XCFLAGS+= -DLUAJIT_UNWIND_EXTERNAL + endif +endif ifeq (Darwin,$(TARGET_SYS)) ifeq (,$(MACOSX_DEPLOYMENT_TARGET)) export MACOSX_DEPLOYMENT_TARGET=10.4 @@ -328,10 +335,6 @@ ifeq (Darwin,$(TARGET_SYS)) TARGET_XSHLDFLAGS= -dynamiclib -single_module -undefined dynamic_lookup -fPIC TARGET_DYNXLDOPTS= TARGET_XSHLDFLAGS+= -install_name $(TARGET_DYLIBPATH) -compatibility_version $(MAJVER).$(MINVER) -current_version $(MAJVER).$(MINVER).$(RELVER) - ifeq (x64,$(TARGET_LJARCH)) - TARGET_XLDFLAGS+= -pagezero_size 10000 -image_base 100000000 - TARGET_XSHLDFLAGS+= -image_base 7fff04c4a000 - endif else ifeq (iOS,$(TARGET_SYS)) TARGET_STRIP+= -x diff --git a/src/lj_arch.h b/src/lj_arch.h index 40129d9e..730be5bf 100644 --- a/src/lj_arch.h +++ b/src/lj_arch.h @@ -152,11 +152,6 @@ #define LJ_ARCH_NAME "x86" #define LJ_ARCH_BITS 32 #define LJ_ARCH_ENDIAN LUAJIT_LE -#if LJ_TARGET_WINDOWS || LJ_TARGET_CYGWIN -#define LJ_ABI_WIN 1 -#else -#define LJ_ABI_WIN 0 -#endif #define LJ_TARGET_X86 1 #define LJ_TARGET_X86ORX64 1 #define LJ_TARGET_EHRETREG 0 @@ -170,11 +165,6 @@ #define LJ_ARCH_NAME "x64" #define LJ_ARCH_BITS 64 #define LJ_ARCH_ENDIAN LUAJIT_LE -#if LJ_TARGET_WINDOWS || LJ_TARGET_CYGWIN -#define LJ_ABI_WIN 1 -#else -#define LJ_ABI_WIN 0 -#endif #define LJ_TARGET_X64 1 #define LJ_TARGET_X86ORX64 1 #define LJ_TARGET_EHRETREG 0 @@ -185,6 +175,8 @@ #define LJ_ARCH_NUMMODE LJ_NUMMODE_SINGLE_DUAL #ifdef LUAJIT_ENABLE_GC64 #define LJ_TARGET_GC64 1 +#elif LJ_TARGET_OSX +#error "macOS requires GC64 -- don't disable it" #endif #elif LUAJIT_TARGET == LUAJIT_ARCH_ARM @@ -566,15 +558,22 @@ #define LJ_NO_SYSTEM 1 #endif -#if !defined(LUAJIT_NO_UNWIND) && __GNU_COMPACT_EH__ -/* NYI: no support for compact unwind specification, yet. */ -#define LUAJIT_NO_UNWIND 1 +#if LJ_TARGET_WINDOWS || LJ_TARGET_CYGWIN +#define LJ_ABI_WIN 1 +#else +#define LJ_ABI_WIN 0 #endif -#if defined(LUAJIT_NO_UNWIND) || defined(__symbian__) || LJ_TARGET_IOS || LJ_TARGET_PS3 || LJ_TARGET_PS4 +#if defined(LUAJIT_NO_UNWIND) || __GNU_COMPACT_EH__ || defined(__symbian__) || LJ_TARGET_IOS || LJ_TARGET_PS3 || LJ_TARGET_PS4 #define LJ_NO_UNWIND 1 #endif +#if !LJ_NO_UNWIND && !defined(LUAJIT_UNWIND_INTERNAL) && (LJ_ABI_WIN || (defined(LUAJIT_UNWIND_EXTERNAL) && (defined(__GNUC__) || defined(__clang__)))) +#define LJ_UNWIND_EXT 1 +#else +#define LJ_UNWIND_EXT 0 +#endif + /* Compatibility with Lua 5.1 vs. 5.2. */ #ifdef LUAJIT_ENABLE_LUA52COMPAT #define LJ_52 1 diff --git a/src/lj_err.c b/src/lj_err.c index c310daf6..298e5434 100644 --- a/src/lj_err.c +++ b/src/lj_err.c @@ -29,12 +29,18 @@ ** Pros and Cons: ** ** - EXT requires unwind tables for *all* functions on the C stack between -** the pcall/catch and the error/throw. This is the default on x64, -** but needs to be manually enabled on x86/PPC for non-C++ code. +** the pcall/catch and the error/throw. C modules used by Lua code can +** throw errors, so these need to have unwind tables, too. Transitively +** this applies to all system libraries used by C modules -- at least +** when they have callbacks which may throw an error. ** -** - INT is faster when actually throwing errors (but this happens rarely). +** - INT is faster when actually throwing errors, but this happens rarely. ** Setting up error handlers is zero-cost in any case. ** +** - INT needs to save *all* callee-saved registers when entering the +** interpreter. EXT only needs to save those actually used inside the +** interpreter. JIT-compiled code may need to save some more. +** ** - EXT provides full interoperability with C++ exceptions. You can throw ** Lua errors or C++ exceptions through a mix of Lua frames and C++ frames. ** C++ destructors are called as needed. C++ exceptions caught by pcall @@ -46,27 +52,33 @@ ** the wrapper function feature. Lua errors thrown through C++ frames ** cannot be caught by C++ code and C++ destructors are not run. ** -** EXT is the default on x64 systems and on Windows, INT is the default on all -** other systems. +** EXT is the default on all systems where the toolchain produces unwind +** tables by default (*). This is hard-coded and/or detected in src/Makefile. +** You can thwart the detection with: TARGET_XCFLAGS=-DLUAJIT_UNWIND_INTERNAL +** +** INT is the default on all other systems. +** +** EXT can be manually enabled for toolchains that are able to produce +** conforming unwind tables: +** "TARGET_XCFLAGS=-funwind-tables -DLUAJIT_UNWIND_EXTERNAL" +** As explained above, *all* C code used directly or indirectly by LuaJIT +** must be compiled with -funwind-tables (or -fexceptions). C++ code must +** *not* be compiled with -fno-exceptions. +** +** If you're unsure whether error handling inside the VM works correctly, +** try running this and check whether it prints "OK": ** -** EXT can be manually enabled on POSIX systems using GCC and DWARF2 stack -** unwinding with -DLUAJIT_UNWIND_EXTERNAL. *All* C code must be compiled -** with -funwind-tables (or -fexceptions). This includes LuaJIT itself (set -** TARGET_CFLAGS), all of your C/Lua binding code, all loadable C modules -** and all C libraries that have callbacks which may be used to call back -** into Lua. C++ code must *not* be compiled with -fno-exceptions. +** luajit -e "print(select(2, load('OK')):match('OK'))" ** -** EXT is mandatory on WIN64 since the calling convention has an abundance -** of callee-saved registers (rbx, rbp, rsi, rdi, r12-r15, xmm6-xmm15). -** The POSIX/x64 interpreter only saves r12/r13 for INT (e.g. PS4). +** (*) Originally, toolchains only generated unwind tables for C++ code. For +** interoperability reasons, this can be manually enabled for plain C code, +** too (with -funwind-tables). With the introduction of the x64 architecture, +** the corresponding POSIX and Windows ABIs mandated unwind tables for all +** code. Over the following years most desktop and server platforms have +** enabled unwind tables by default on all architectures. OTOH mobile and +** embedded platforms do not consistently mandate unwind tables. */ -#if defined(__GNUC__) && (LJ_TARGET_X64 || defined(LUAJIT_UNWIND_EXTERNAL)) && !LJ_NO_UNWIND -#define LJ_UNWIND_EXT 1 -#elif LJ_TARGET_WINDOWS -#define LJ_UNWIND_EXT 1 -#endif - /* -- Error messages ------------------------------------------------------ */ /* Error message strings. */ @@ -183,7 +195,125 @@ static void *err_unwind(lua_State *L, void *stopcf, int errcode) /* -- External frame unwinding -------------------------------------------- */ -#if defined(__GNUC__) && !LJ_NO_UNWIND && !LJ_ABI_WIN +#if LJ_ABI_WIN + +/* +** Someone in Redmond owes me several days of my life. A lot of this is +** undocumented or just plain wrong on MSDN. Some of it can be gathered +** from 3rd party docs or must be found by trial-and-error. They really +** don't want you to write your own language-specific exception handler +** or to interact gracefully with MSVC. :-( +** +** Apparently MSVC doesn't call C++ destructors for foreign exceptions +** unless you compile your C++ code with /EHa. Unfortunately this means +** catch (...) also catches things like access violations. The use of +** _set_se_translator doesn't really help, because it requires /EHa, too. +*/ + +#define WIN32_LEAN_AND_MEAN +#include + +#if LJ_TARGET_X86 +typedef void *UndocumentedDispatcherContext; /* Unused on x86. */ +#else +/* Taken from: http://www.nynaeve.net/?p=99 */ +typedef struct UndocumentedDispatcherContext { + ULONG64 ControlPc; + ULONG64 ImageBase; + PRUNTIME_FUNCTION FunctionEntry; + ULONG64 EstablisherFrame; + ULONG64 TargetIp; + PCONTEXT ContextRecord; + void (*LanguageHandler)(void); + PVOID HandlerData; + PUNWIND_HISTORY_TABLE HistoryTable; + ULONG ScopeIndex; + ULONG Fill0; +} UndocumentedDispatcherContext; +#endif + +/* Another wild guess. */ +extern void __DestructExceptionObject(EXCEPTION_RECORD *rec, int nothrow); + +#if LJ_TARGET_X64 && defined(MINGW_SDK_INIT) +/* Workaround for broken MinGW64 declaration. */ +VOID RtlUnwindEx_FIXED(PVOID,PVOID,PVOID,PVOID,PVOID,PVOID) asm("RtlUnwindEx"); +#define RtlUnwindEx RtlUnwindEx_FIXED +#endif + +#define LJ_MSVC_EXCODE ((DWORD)0xe06d7363) +#define LJ_GCC_EXCODE ((DWORD)0x20474343) + +#define LJ_EXCODE ((DWORD)0xe24c4a00) +#define LJ_EXCODE_MAKE(c) (LJ_EXCODE | (DWORD)(c)) +#define LJ_EXCODE_CHECK(cl) (((cl) ^ LJ_EXCODE) <= 0xff) +#define LJ_EXCODE_ERRCODE(cl) ((int)((cl) & 0xff)) + +/* Windows exception handler for interpreter frame. */ +LJ_FUNCA int lj_err_unwind_win(EXCEPTION_RECORD *rec, + void *f, CONTEXT *ctx, UndocumentedDispatcherContext *dispatch) +{ +#if LJ_TARGET_X86 + void *cf = (char *)f - CFRAME_OFS_SEH; +#else + void *cf = f; +#endif + lua_State *L = cframe_L(cf); + int errcode = LJ_EXCODE_CHECK(rec->ExceptionCode) ? + LJ_EXCODE_ERRCODE(rec->ExceptionCode) : LUA_ERRRUN; + if ((rec->ExceptionFlags & 6)) { /* EH_UNWINDING|EH_EXIT_UNWIND */ + /* Unwind internal frames. */ + err_unwind(L, cf, errcode); + } else { + void *cf2 = err_unwind(L, cf, 0); + if (cf2) { /* We catch it, so start unwinding the upper frames. */ + if (rec->ExceptionCode == LJ_MSVC_EXCODE || + rec->ExceptionCode == LJ_GCC_EXCODE) { +#if !LJ_TARGET_CYGWIN + __DestructExceptionObject(rec, 1); +#endif + setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRCPP)); + } else if (!LJ_EXCODE_CHECK(rec->ExceptionCode)) { + /* Don't catch access violations etc. */ + return 1; /* ExceptionContinueSearch */ + } +#if LJ_TARGET_X86 + UNUSED(ctx); + UNUSED(dispatch); + /* Call all handlers for all lower C frames (including ourselves) again + ** with EH_UNWINDING set. Then call the specified function, passing cf + ** and errcode. + */ + lj_vm_rtlunwind(cf, (void *)rec, + (cframe_unwind_ff(cf2) && errcode != LUA_YIELD) ? + (void *)lj_vm_unwind_ff : (void *)lj_vm_unwind_c, errcode); + /* lj_vm_rtlunwind does not return. */ +#else + /* Unwind the stack and call all handlers for all lower C frames + ** (including ourselves) again with EH_UNWINDING set. Then set + ** stack pointer = cf, result = errcode and jump to the specified target. + */ + RtlUnwindEx(cf, (void *)((cframe_unwind_ff(cf2) && errcode != LUA_YIELD) ? + lj_vm_unwind_ff_eh : + lj_vm_unwind_c_eh), + rec, (void *)(uintptr_t)errcode, ctx, dispatch->HistoryTable); + /* RtlUnwindEx should never return. */ +#endif + } + } + return 1; /* ExceptionContinueSearch */ +} + +/* Raise Windows exception. */ +static void err_raise_ext(global_State *g, int errcode) +{ +#if LJ_HASJIT + setmref(g->jit_base, NULL); +#endif + RaiseException(LJ_EXCODE_MAKE(errcode), 1 /* EH_NONCONTINUABLE */, 0, NULL); +} + +#elif !LJ_NO_UNWIND && (defined(__GNUC__) || defined(__clang__)) /* ** We have to use our own definitions instead of the mandatory (!) unwind.h, @@ -232,7 +362,6 @@ LJ_FUNCA int lj_err_unwind_dwarf(int version, int actions, lua_State *L; if (version != 1) return _URC_FATAL_PHASE1_ERROR; - UNUSED(uexclass); cf = (void *)_Unwind_GetCFA(ctx); L = cframe_L(cf); if ((actions & _UA_SEARCH_PHASE)) { @@ -280,6 +409,9 @@ LJ_FUNCA int lj_err_unwind_dwarf(int version, int actions, ** it on non-x64 because the interpreter restores all callee-saved regs. */ lj_err_throw(L, errcode); +#if LJ_TARGET_X64 +#error "Broken build system -- only use the provided Makefiles!" +#endif #endif } return _URC_CONTINUE_UNWIND; @@ -292,14 +424,6 @@ static _Unwind_Exception static_uex; #else static __thread _Unwind_Exception static_uex; #endif - -/* Raise DWARF2 exception. */ -static void err_raise_ext(int errcode) -{ - static_uex.exclass = LJ_UEXCLASS_MAKE(errcode); - static_uex.excleanup = NULL; - _Unwind_RaiseException(&static_uex); -} #endif #else /* LJ_TARGET_ARM */ @@ -373,132 +497,22 @@ LJ_FUNCA int lj_err_unwind_arm(int state, _Unwind_Control_Block *ucb, #if LJ_UNWIND_EXT static __thread _Unwind_Control_Block static_uex; +#endif +#endif /* LJ_TARGET_ARM */ -static void err_raise_ext(int errcode) +#if LJ_UNWIND_EXT +/* Raise external exception. */ +static void err_raise_ext(global_State *g, int errcode) { +#if LJ_HASJIT + setmref(g->jit_base, NULL); +#endif memset(&static_uex, 0, sizeof(static_uex)); static_uex.exclass = LJ_UEXCLASS_MAKE(errcode); _Unwind_RaiseException(&static_uex); } #endif -#endif /* LJ_TARGET_ARM */ - -#elif LJ_ABI_WIN - -/* -** Someone in Redmond owes me several days of my life. A lot of this is -** undocumented or just plain wrong on MSDN. Some of it can be gathered -** from 3rd party docs or must be found by trial-and-error. They really -** don't want you to write your own language-specific exception handler -** or to interact gracefully with MSVC. :-( -** -** Apparently MSVC doesn't call C++ destructors for foreign exceptions -** unless you compile your C++ code with /EHa. Unfortunately this means -** catch (...) also catches things like access violations. The use of -** _set_se_translator doesn't really help, because it requires /EHa, too. -*/ - -#define WIN32_LEAN_AND_MEAN -#include - -#if LJ_TARGET_X64 -/* Taken from: http://www.nynaeve.net/?p=99 */ -typedef struct UndocumentedDispatcherContext { - ULONG64 ControlPc; - ULONG64 ImageBase; - PRUNTIME_FUNCTION FunctionEntry; - ULONG64 EstablisherFrame; - ULONG64 TargetIp; - PCONTEXT ContextRecord; - void (*LanguageHandler)(void); - PVOID HandlerData; - PUNWIND_HISTORY_TABLE HistoryTable; - ULONG ScopeIndex; - ULONG Fill0; -} UndocumentedDispatcherContext; -#else -typedef void *UndocumentedDispatcherContext; -#endif - -/* Another wild guess. */ -extern void __DestructExceptionObject(EXCEPTION_RECORD *rec, int nothrow); - -#if LJ_TARGET_X64 && defined(MINGW_SDK_INIT) -/* Workaround for broken MinGW64 declaration. */ -VOID RtlUnwindEx_FIXED(PVOID,PVOID,PVOID,PVOID,PVOID,PVOID) asm("RtlUnwindEx"); -#define RtlUnwindEx RtlUnwindEx_FIXED -#endif - -#define LJ_MSVC_EXCODE ((DWORD)0xe06d7363) -#define LJ_GCC_EXCODE ((DWORD)0x20474343) - -#define LJ_EXCODE ((DWORD)0xe24c4a00) -#define LJ_EXCODE_MAKE(c) (LJ_EXCODE | (DWORD)(c)) -#define LJ_EXCODE_CHECK(cl) (((cl) ^ LJ_EXCODE) <= 0xff) -#define LJ_EXCODE_ERRCODE(cl) ((int)((cl) & 0xff)) - -/* Windows exception handler for interpreter frame. */ -LJ_FUNCA int lj_err_unwind_win(EXCEPTION_RECORD *rec, - void *f, CONTEXT *ctx, UndocumentedDispatcherContext *dispatch) -{ -#if LJ_TARGET_X64 - void *cf = f; -#else - void *cf = (char *)f - CFRAME_OFS_SEH; -#endif - lua_State *L = cframe_L(cf); - int errcode = LJ_EXCODE_CHECK(rec->ExceptionCode) ? - LJ_EXCODE_ERRCODE(rec->ExceptionCode) : LUA_ERRRUN; - if ((rec->ExceptionFlags & 6)) { /* EH_UNWINDING|EH_EXIT_UNWIND */ - /* Unwind internal frames. */ - err_unwind(L, cf, errcode); - } else { - void *cf2 = err_unwind(L, cf, 0); - if (cf2) { /* We catch it, so start unwinding the upper frames. */ - if (rec->ExceptionCode == LJ_MSVC_EXCODE || - rec->ExceptionCode == LJ_GCC_EXCODE) { -#if LJ_TARGET_WINDOWS - __DestructExceptionObject(rec, 1); -#endif - setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRCPP)); - } else if (!LJ_EXCODE_CHECK(rec->ExceptionCode)) { - /* Don't catch access violations etc. */ - return 1; /* ExceptionContinueSearch */ - } -#if LJ_TARGET_X64 - /* Unwind the stack and call all handlers for all lower C frames - ** (including ourselves) again with EH_UNWINDING set. Then set - ** rsp = cf, rax = errcode and jump to the specified target. - */ - RtlUnwindEx(cf, (void *)((cframe_unwind_ff(cf2) && errcode != LUA_YIELD) ? - lj_vm_unwind_ff_eh : - lj_vm_unwind_c_eh), - rec, (void *)(uintptr_t)errcode, ctx, dispatch->HistoryTable); - /* RtlUnwindEx should never return. */ -#else - UNUSED(ctx); - UNUSED(dispatch); - /* Call all handlers for all lower C frames (including ourselves) again - ** with EH_UNWINDING set. Then call the specified function, passing cf - ** and errcode. - */ - lj_vm_rtlunwind(cf, (void *)rec, - (cframe_unwind_ff(cf2) && errcode != LUA_YIELD) ? - (void *)lj_vm_unwind_ff : (void *)lj_vm_unwind_c, errcode); - /* lj_vm_rtlunwind does not return. */ -#endif - } - } - return 1; /* ExceptionContinueSearch */ -} - -/* Raise Windows exception. */ -static void err_raise_ext(int errcode) -{ - RaiseException(LJ_EXCODE_MAKE(errcode), 1 /* EH_NONCONTINUABLE */, 0, NULL); -} - #endif /* -- Error handling ------------------------------------------------------ */ @@ -508,22 +522,23 @@ LJ_NOINLINE void LJ_FASTCALL lj_err_throw(lua_State *L, int errcode) { global_State *g = G(L); lj_trace_abort(g); - setmref(g->jit_base, NULL); L->status = LUA_OK; #if LJ_UNWIND_EXT - err_raise_ext(errcode); + err_raise_ext(g, errcode); /* ** A return from this function signals a corrupt C stack that cannot be ** unwound. We have no choice but to call the panic function and exit. ** ** Usually this is caused by a C function without unwind information. - ** This should never happen on x64, but may happen if you've manually - ** enabled LUAJIT_UNWIND_EXTERNAL and forgot to recompile *every* - ** non-C++ file with -funwind-tables. + ** This may happen if you've manually enabled LUAJIT_UNWIND_EXTERNAL + ** and forgot to recompile *every* non-C++ file with -funwind-tables. */ if (G(L)->panic) G(L)->panic(L); #else +#if LJ_HASJIT + setmref(g->jit_base, NULL); +#endif { void *cf = err_unwind(L, NULL, errcode); if (cframe_unwind_ff(cf)) -- 2.32.1 (Apple Git-133)