]> git.ipfire.org Git - thirdparty/LuaJIT.git/commitdiff
Windows: Call C++ destructors without compiling with /EHa.
authorMike Pall <mike>
Fri, 15 Sep 2023 03:47:29 +0000 (05:47 +0200)
committerMike Pall <mike>
Fri, 15 Sep 2023 03:47:29 +0000 (05:47 +0200)
Thanks to Peter Cawley. #593

doc/extensions.html
src/lj_err.c

index eb591d1e758013c512eb984514c986ac23b92111..a4f20841a06bc5b52e733d8dd6501173adc66c70 100644 (file)
@@ -426,9 +426,7 @@ the toolchain used to compile LuaJIT:
 on the C&nbsp;stack. The contents of the C++&nbsp;exception object
 pass through unmodified.</li>
 <li>Lua errors can be caught on the C++ side with <tt>catch(...)</tt>.
-The corresponding Lua error message can be retrieved from the Lua stack.<br>
-For MSVC for Windows 64 bit this requires compilation of your C++ code
-with <tt>/EHa</tt>.</li>
+The corresponding Lua error message can be retrieved from the Lua stack.</li>
 <li>Throwing Lua errors across C++ frames is safe. C++ destructors
 will be called.</li>
 </ul>
index 9677a1b002dbc5e929c8ef101edee99000eaff89..cadc76bdb782f3f0cc1fa186b21498997c4ccc1f 100644 (file)
@@ -209,11 +209,6 @@ static void *err_unwind(lua_State *L, void *stopcf, int errcode)
 ** 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
@@ -270,11 +265,25 @@ LJ_FUNCA int lj_err_unwind_win(EXCEPTION_RECORD *rec,
   int errcode = LJ_EXCODE_CHECK(rec->ExceptionCode) ?
                LJ_EXCODE_ERRCODE(rec->ExceptionCode) : LUA_ERRRUN;
   if ((rec->ExceptionFlags & 6)) {  /* EH_UNWINDING|EH_EXIT_UNWIND */
+    if (rec->ExceptionCode == STATUS_LONGJUMP &&
+       rec->ExceptionRecord &&
+       LJ_EXCODE_CHECK(rec->ExceptionRecord->ExceptionCode)) {
+      errcode = LJ_EXCODE_ERRCODE(rec->ExceptionRecord->ExceptionCode);
+      if ((rec->ExceptionFlags & 0x20)) {  /* EH_TARGET_UNWIND */
+       /* Unwinding is about to finish; revert the ExceptionCode so that
+       ** RtlRestoreContext does not try to restore from a _JUMP_BUFFER.
+       */
+       rec->ExceptionCode = 0;
+      }
+    }
     /* 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 !LJ_TARGET_X86
+      EXCEPTION_RECORD rec2;
+#endif
       if (rec->ExceptionCode == LJ_MSVC_EXCODE ||
          rec->ExceptionCode == LJ_GCC_EXCODE) {
 #if !LJ_TARGET_CYGWIN
@@ -285,8 +294,8 @@ LJ_FUNCA int lj_err_unwind_win(EXCEPTION_RECORD *rec,
        /* Don't catch access violations etc. */
        return 1;  /* ExceptionContinueSearch */
       }
-      UNUSED(ctx);
 #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
@@ -297,6 +306,20 @@ LJ_FUNCA int lj_err_unwind_win(EXCEPTION_RECORD *rec,
        (void *)lj_vm_unwind_ff : (void *)lj_vm_unwind_c, errcode);
       /* lj_vm_rtlunwind does not return. */
 #else
+      if (LJ_EXCODE_CHECK(rec->ExceptionCode)) {
+       /* For unwind purposes, wrap the EXCEPTION_RECORD in something that
+       ** looks like a longjmp, so that MSVC will execute C++ destructors in
+       ** the frames we unwind over. ExceptionInformation[0] should really
+       ** contain a _JUMP_BUFFER*, but hopefully nobody is looking too closely
+       ** at this point.
+       */
+       rec2.ExceptionCode = STATUS_LONGJUMP;
+       rec2.ExceptionRecord = rec;
+       rec2.ExceptionAddress = 0;
+       rec2.NumberParameters = 1;
+       rec2.ExceptionInformation[0] = (ULONG_PTR)ctx;
+       rec = &rec2;
+      }
       /* Unwind the stack and call all handlers for all lower C frames
       ** (including ourselves) again with EH_UNWINDING set. Then set
       ** stack pointer = f, result = errcode and jump to the specified target.