aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Pall <mike>2023-09-15 05:47:29 +0200
committerMike Pall <mike>2023-09-15 05:47:29 +0200
commitbd2d10715165b89d30e46c5075aed725705dfe5b (patch)
tree54ce5d74ff289e21ad93b4a14e53a78491d06949
parent7a1c139569874f371f567d060738a3f5704930a1 (diff)
downloadluajit-bd2d10715165b89d30e46c5075aed725705dfe5b.tar.gz
luajit-bd2d10715165b89d30e46c5075aed725705dfe5b.tar.bz2
luajit-bd2d10715165b89d30e46c5075aed725705dfe5b.zip
Windows: Call C++ destructors without compiling with /EHa.
Thanks to Peter Cawley. #593
-rw-r--r--doc/extensions.html4
-rw-r--r--src/lj_err.c35
2 files changed, 30 insertions, 9 deletions
diff --git a/doc/extensions.html b/doc/extensions.html
index eb591d1e..a4f20841 100644
--- a/doc/extensions.html
+++ b/doc/extensions.html
@@ -426,9 +426,7 @@ the toolchain used to compile LuaJIT:
426on the C&nbsp;stack. The contents of the C++&nbsp;exception object 426on the C&nbsp;stack. The contents of the C++&nbsp;exception object
427pass through unmodified.</li> 427pass through unmodified.</li>
428<li>Lua errors can be caught on the C++ side with <tt>catch(...)</tt>. 428<li>Lua errors can be caught on the C++ side with <tt>catch(...)</tt>.
429The corresponding Lua error message can be retrieved from the Lua stack.<br> 429The corresponding Lua error message can be retrieved from the Lua stack.</li>
430For MSVC for Windows 64 bit this requires compilation of your C++ code
431with <tt>/EHa</tt>.</li>
432<li>Throwing Lua errors across C++ frames is safe. C++ destructors 430<li>Throwing Lua errors across C++ frames is safe. C++ destructors
433will be called.</li> 431will be called.</li>
434</ul> 432</ul>
diff --git a/src/lj_err.c b/src/lj_err.c
index 9677a1b0..cadc76bd 100644
--- a/src/lj_err.c
+++ b/src/lj_err.c
@@ -209,11 +209,6 @@ static void *err_unwind(lua_State *L, void *stopcf, int errcode)
209** from 3rd party docs or must be found by trial-and-error. They really 209** from 3rd party docs or must be found by trial-and-error. They really
210** don't want you to write your own language-specific exception handler 210** don't want you to write your own language-specific exception handler
211** or to interact gracefully with MSVC. :-( 211** or to interact gracefully with MSVC. :-(
212**
213** Apparently MSVC doesn't call C++ destructors for foreign exceptions
214** unless you compile your C++ code with /EHa. Unfortunately this means
215** catch (...) also catches things like access violations. The use of
216** _set_se_translator doesn't really help, because it requires /EHa, too.
217*/ 212*/
218 213
219#define WIN32_LEAN_AND_MEAN 214#define WIN32_LEAN_AND_MEAN
@@ -270,11 +265,25 @@ LJ_FUNCA int lj_err_unwind_win(EXCEPTION_RECORD *rec,
270 int errcode = LJ_EXCODE_CHECK(rec->ExceptionCode) ? 265 int errcode = LJ_EXCODE_CHECK(rec->ExceptionCode) ?
271 LJ_EXCODE_ERRCODE(rec->ExceptionCode) : LUA_ERRRUN; 266 LJ_EXCODE_ERRCODE(rec->ExceptionCode) : LUA_ERRRUN;
272 if ((rec->ExceptionFlags & 6)) { /* EH_UNWINDING|EH_EXIT_UNWIND */ 267 if ((rec->ExceptionFlags & 6)) { /* EH_UNWINDING|EH_EXIT_UNWIND */
268 if (rec->ExceptionCode == STATUS_LONGJUMP &&
269 rec->ExceptionRecord &&
270 LJ_EXCODE_CHECK(rec->ExceptionRecord->ExceptionCode)) {
271 errcode = LJ_EXCODE_ERRCODE(rec->ExceptionRecord->ExceptionCode);
272 if ((rec->ExceptionFlags & 0x20)) { /* EH_TARGET_UNWIND */
273 /* Unwinding is about to finish; revert the ExceptionCode so that
274 ** RtlRestoreContext does not try to restore from a _JUMP_BUFFER.
275 */
276 rec->ExceptionCode = 0;
277 }
278 }
273 /* Unwind internal frames. */ 279 /* Unwind internal frames. */
274 err_unwind(L, cf, errcode); 280 err_unwind(L, cf, errcode);
275 } else { 281 } else {
276 void *cf2 = err_unwind(L, cf, 0); 282 void *cf2 = err_unwind(L, cf, 0);
277 if (cf2) { /* We catch it, so start unwinding the upper frames. */ 283 if (cf2) { /* We catch it, so start unwinding the upper frames. */
284#if !LJ_TARGET_X86
285 EXCEPTION_RECORD rec2;
286#endif
278 if (rec->ExceptionCode == LJ_MSVC_EXCODE || 287 if (rec->ExceptionCode == LJ_MSVC_EXCODE ||
279 rec->ExceptionCode == LJ_GCC_EXCODE) { 288 rec->ExceptionCode == LJ_GCC_EXCODE) {
280#if !LJ_TARGET_CYGWIN 289#if !LJ_TARGET_CYGWIN
@@ -285,8 +294,8 @@ LJ_FUNCA int lj_err_unwind_win(EXCEPTION_RECORD *rec,
285 /* Don't catch access violations etc. */ 294 /* Don't catch access violations etc. */
286 return 1; /* ExceptionContinueSearch */ 295 return 1; /* ExceptionContinueSearch */
287 } 296 }
288 UNUSED(ctx);
289#if LJ_TARGET_X86 297#if LJ_TARGET_X86
298 UNUSED(ctx);
290 UNUSED(dispatch); 299 UNUSED(dispatch);
291 /* Call all handlers for all lower C frames (including ourselves) again 300 /* Call all handlers for all lower C frames (including ourselves) again
292 ** with EH_UNWINDING set. Then call the specified function, passing cf 301 ** 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,
297 (void *)lj_vm_unwind_ff : (void *)lj_vm_unwind_c, errcode); 306 (void *)lj_vm_unwind_ff : (void *)lj_vm_unwind_c, errcode);
298 /* lj_vm_rtlunwind does not return. */ 307 /* lj_vm_rtlunwind does not return. */
299#else 308#else
309 if (LJ_EXCODE_CHECK(rec->ExceptionCode)) {
310 /* For unwind purposes, wrap the EXCEPTION_RECORD in something that
311 ** looks like a longjmp, so that MSVC will execute C++ destructors in
312 ** the frames we unwind over. ExceptionInformation[0] should really
313 ** contain a _JUMP_BUFFER*, but hopefully nobody is looking too closely
314 ** at this point.
315 */
316 rec2.ExceptionCode = STATUS_LONGJUMP;
317 rec2.ExceptionRecord = rec;
318 rec2.ExceptionAddress = 0;
319 rec2.NumberParameters = 1;
320 rec2.ExceptionInformation[0] = (ULONG_PTR)ctx;
321 rec = &rec2;
322 }
300 /* Unwind the stack and call all handlers for all lower C frames 323 /* Unwind the stack and call all handlers for all lower C frames
301 ** (including ourselves) again with EH_UNWINDING set. Then set 324 ** (including ourselves) again with EH_UNWINDING set. Then set
302 ** stack pointer = f, result = errcode and jump to the specified target. 325 ** stack pointer = f, result = errcode and jump to the specified target.