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
|
on the C stack. The contents of the C++ exception object
|
||||||
pass through unmodified.</li>
|
pass through unmodified.</li>
|
||||||
<li>Lua errors can be caught on the C++ side with <tt>catch(...)</tt>.
|
<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>
|
The corresponding Lua error message can be retrieved from the Lua stack.</li>
|
||||||
For MSVC for Windows 64 bit this requires compilation of your C++ code
|
|
||||||
with <tt>/EHa</tt>.</li>
|
|
||||||
<li>Throwing Lua errors across C++ frames is safe. C++ destructors
|
<li>Throwing Lua errors across C++ frames is safe. C++ destructors
|
||||||
will be called.</li>
|
will be called.</li>
|
||||||
</ul>
|
</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
|
** 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
|
** don't want you to write your own language-specific exception handler
|
||||||
** or to interact gracefully with MSVC. :-(
|
** 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
|
#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) ?
|
int errcode = LJ_EXCODE_CHECK(rec->ExceptionCode) ?
|
||||||
LJ_EXCODE_ERRCODE(rec->ExceptionCode) : LUA_ERRRUN;
|
LJ_EXCODE_ERRCODE(rec->ExceptionCode) : LUA_ERRRUN;
|
||||||
if ((rec->ExceptionFlags & 6)) { /* EH_UNWINDING|EH_EXIT_UNWIND */
|
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. */
|
/* Unwind internal frames. */
|
||||||
err_unwind(L, cf, errcode);
|
err_unwind(L, cf, errcode);
|
||||||
} else {
|
} else {
|
||||||
void *cf2 = err_unwind(L, cf, 0);
|
void *cf2 = err_unwind(L, cf, 0);
|
||||||
if (cf2) { /* We catch it, so start unwinding the upper frames. */
|
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 ||
|
if (rec->ExceptionCode == LJ_MSVC_EXCODE ||
|
||||||
rec->ExceptionCode == LJ_GCC_EXCODE) {
|
rec->ExceptionCode == LJ_GCC_EXCODE) {
|
||||||
#if !LJ_TARGET_CYGWIN
|
#if !LJ_TARGET_CYGWIN
|
||||||
@ -285,8 +294,8 @@ LJ_FUNCA int lj_err_unwind_win(EXCEPTION_RECORD *rec,
|
|||||||
/* Don't catch access violations etc. */
|
/* Don't catch access violations etc. */
|
||||||
return 1; /* ExceptionContinueSearch */
|
return 1; /* ExceptionContinueSearch */
|
||||||
}
|
}
|
||||||
UNUSED(ctx);
|
|
||||||
#if LJ_TARGET_X86
|
#if LJ_TARGET_X86
|
||||||
|
UNUSED(ctx);
|
||||||
UNUSED(dispatch);
|
UNUSED(dispatch);
|
||||||
/* Call all handlers for all lower C frames (including ourselves) again
|
/* Call all handlers for all lower C frames (including ourselves) again
|
||||||
** with EH_UNWINDING set. Then call the specified function, passing cf
|
** 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);
|
(void *)lj_vm_unwind_ff : (void *)lj_vm_unwind_c, errcode);
|
||||||
/* lj_vm_rtlunwind does not return. */
|
/* lj_vm_rtlunwind does not return. */
|
||||||
#else
|
#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
|
/* Unwind the stack and call all handlers for all lower C frames
|
||||||
** (including ourselves) again with EH_UNWINDING set. Then set
|
** (including ourselves) again with EH_UNWINDING set. Then set
|
||||||
** stack pointer = f, result = errcode and jump to the specified target.
|
** stack pointer = f, result = errcode and jump to the specified target.
|
||||||
|
Loading…
Reference in New Issue
Block a user