Fix crash in mono mini exceptions.exe regression test on win x64.
authorlateralusX <lateralusx.github@gmail.com>
Thu, 7 Jul 2016 15:24:49 +0000 (17:24 +0200)
committerlateralusX <lateralusx.github@gmail.com>
Thu, 7 Jul 2016 15:24:49 +0000 (17:24 +0200)
Exceptions.exe regression test started to fail on win x64 release builds.
Turns out that the Visual Studio C compiler picked a different optimization
for release builds (due to a change of library type that uses a different default optimization level)
using RSI register in native code calling into JIT:ed code. If the JIT:ed code used reflection
and exceptions, that triggers InternalInvoke and lmf_filter, the code only
stored System V x64 non-volatile registers in the unwind information. On Windows,
RSI is also a non-volatile register (RDI as well) that needs to be preserved and
since the code didn’t include those in the unwind information, the correct RSI value
was not restored during the unwind. Once the control was handled back to the native
code it dereferenced RSI (that was set to 0) and crashed.

The fix is to make sure we store all non-volatile registers on x64 Windows
when we save an lmf so the unwind code can restore them when unwinding through
the lmf.

mono/mini/mini-amd64.c

index 054aa4017ae78ffbf5b3b7400b9254546a863770..932f198a7793a66e8d8ef33b962d5a2705afc5c1 100644 (file)
@@ -1550,9 +1550,11 @@ mono_arch_allocate_vars (MonoCompile *cfg)
        }
 
        cfg->arch.saved_iregs = cfg->used_int_regs;
-       if (cfg->method->save_lmf)
-               /* Save all callee-saved registers normally, and restore them when unwinding through an LMF */
-               cfg->arch.saved_iregs |= (1 << AMD64_RBX) | (1 << AMD64_R12) | (1 << AMD64_R13) | (1 << AMD64_R14) | (1 << AMD64_R15);
+       if (cfg->method->save_lmf) {
+               /* Save all callee-saved registers normally (except RBP, if not already used), and restore them when unwinding through an LMF */
+               guint32 iregs_to_save = AMD64_CALLEE_SAVED_REGS & ~(1<<AMD64_RBP);
+               cfg->arch.saved_iregs |= iregs_to_save;
+       }
 
        if (cfg->arch.omit_fp)
                cfg->arch.reg_save_area_offset = offset;