mirror of
https://github.com/LuaJIT/LuaJIT.git
synced 2025-02-07 15:14:08 +00:00
Windows: Call C++ destructors without compiling with /EHa.
Thanks to Peter Cawley. #593
This commit is contained in:
parent
7a1c139569
commit
bd2d107151
@ -426,9 +426,7 @@ the toolchain used to compile LuaJIT:
|
||||
on the C stack. The contents of the C++ 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>
|
||||
|
35
src/lj_err.c
35
src/lj_err.c
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user