From 8401610bb0a8cf5743c3cfa1eaa08eeab5eeada4 Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Sat, 14 Apr 2018 01:14:27 +0300 Subject: [PATCH] [interp] Exit from finally abort protected block when EH (#8207) Fixes https://github.com/mono/mono/issues/7402 --- .../corlib/Test/System.Threading/ThreadTest.cs | 1 - mono/mini/interp/interp.c | 1 - mono/mini/interp/transform.c | 1 + mono/mini/mini-exceptions.c | 30 ++++++++++++++++++++++ 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/mcs/class/corlib/Test/System.Threading/ThreadTest.cs b/mcs/class/corlib/Test/System.Threading/ThreadTest.cs index 317cfe4da6e..8969ca9862e 100644 --- a/mcs/class/corlib/Test/System.Threading/ThreadTest.cs +++ b/mcs/class/corlib/Test/System.Threading/ThreadTest.cs @@ -835,7 +835,6 @@ namespace MonoTests.System.Threading #endif [Test] - [Category ("NotWorkingRuntimeInterpreter")] public void Test_Interrupt () { ManualResetEvent mre = new ManualResetEvent (false); diff --git a/mono/mini/interp/interp.c b/mono/mini/interp/interp.c index 71005d8db11..6891d30e0c7 100644 --- a/mono/mini/interp/interp.c +++ b/mono/mini/interp/interp.c @@ -4461,7 +4461,6 @@ array_constructed: ip ++; MINT_IN_BREAK; MINT_IN_CASE(MINT_END_ABORT_PROT) - /* FIXME We miss it if exception is thrown in finally clause */ mono_threads_end_abort_protected_block (); ip ++; MINT_IN_BREAK; diff --git a/mono/mini/interp/transform.c b/mono/mini/interp/transform.c index e400833eb9c..6fd0abcb2ff 100644 --- a/mono/mini/interp/transform.c +++ b/mono/mini/interp/transform.c @@ -4539,6 +4539,7 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, unsig if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) { ei->data.filter = (guint8*)(rtm->code + c->data.filter_offset); } else if (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) { + ei->data.handler_end = (guint8*)(rtm->code + c->handler_offset + c->handler_len); } else { ei->data.catch_class = c->data.catch_class; } diff --git a/mono/mini/mini-exceptions.c b/mono/mini/mini-exceptions.c index c785cfe9e44..2698ddda786 100644 --- a/mono/mini/mini-exceptions.c +++ b/mono/mini/mini-exceptions.c @@ -1876,6 +1876,32 @@ handle_exception_first_pass (MonoContext *ctx, MonoObject *obj, gint32 *out_filt g_assert_not_reached (); } +/* + * We implement delaying of aborts when in finally blocks by reusing the + * abort protected block mechanism. The problem is that when throwing an + * exception in a finally block we don't get to exit the protected block. + * We exit it here when unwinding. Given that the order of the clauses + * in the jit info is from inner clauses to the outer clauses, when we + * want to exit the finally blocks inner to the clause that handles the + * exception, we need to search up to its index. + * + * FIXME We should do this inside interp, but with mixed mode we can + * resume directly, without giving control back to the interp. + */ +static void +interp_exit_finally_abort_blocks (MonoJitInfo *ji, int start_clause, int end_clause, gpointer ip) +{ + int i; + for (i = start_clause; i < end_clause; i++) { + MonoJitExceptionInfo *ei = &ji->clauses [i]; + if (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY && + ip >= ei->handler_start && + ip < ei->data.handler_end) { + mono_threads_end_abort_protected_block (); + } + } +} + /** * mono_handle_exception_internal: * \param ctx saved processor state @@ -2251,6 +2277,7 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu mini_set_abort_threshold (&frame); if (in_interp) { + interp_exit_finally_abort_blocks (ji, clause_index_start, i, ip); /* * ctx->pc points into the interpreter, after the call which transitioned to * JITted code. Store the unwind state into the @@ -2338,6 +2365,9 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu } } + if (in_interp) + interp_exit_finally_abort_blocks (ji, clause_index_start, ji->num_clauses, ip); + if (MONO_PROFILER_ENABLED (method_exception_leave) && mono_profiler_get_call_instrumentation_flags (method) & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE) { jit_tls->orig_ex_ctx_set = TRUE; -- 2.11.4.GIT