diff options
author | Mike Pall <mike> | 2023-09-15 05:47:29 +0200 |
---|---|---|
committer | Mike Pall <mike> | 2023-09-15 05:47:29 +0200 |
commit | bd2d10715165b89d30e46c5075aed725705dfe5b (patch) | |
tree | 54ce5d74ff289e21ad93b4a14e53a78491d06949 | |
parent | 7a1c139569874f371f567d060738a3f5704930a1 (diff) | |
download | luajit-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.html | 4 | ||||
-rw-r--r-- | src/lj_err.c | 35 |
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: | |||
426 | on the C stack. The contents of the C++ exception object | 426 | on the C stack. The contents of the C++ exception object |
427 | pass through unmodified.</li> | 427 | pass 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>. |
429 | The corresponding Lua error message can be retrieved from the Lua stack.<br> | 429 | The corresponding Lua error message can be retrieved from the Lua stack.</li> |
430 | For MSVC for Windows 64 bit this requires compilation of your C++ code | ||
431 | with <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 |
433 | will be called.</li> | 431 | will 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. |