Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions mono/metadata/object-internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,7 @@ typedef struct {
void (*mono_raise_exception_with_ctx) (MonoException *ex, MonoContext *ctx);
gboolean (*mono_exception_walk_trace) (MonoException *ex, MonoInternalExceptionFrameWalk func, gpointer user_data);
gboolean (*mono_install_handler_block_guard) (MonoThreadUnwindState *unwind_state);
void (*mono_uninstall_current_handler_block_guard) (void);
gboolean (*mono_current_thread_has_handle_block_guard) (void);
gboolean (*mono_above_abort_threshold) (void);
void (*mono_clear_abort_threshold) (void);
Expand Down
2 changes: 1 addition & 1 deletion mono/metadata/threads-types.h
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ void mono_threads_set_shutting_down (void);
gunichar2* mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len);

MONO_API MonoException* mono_thread_get_undeniable_exception (void);
void mono_thread_self_abort (void);
void ves_icall_thread_finish_async_abort (void);

MONO_PROFILER_API void mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean permanent, gboolean reset, MonoError *error);

Expand Down
73 changes: 68 additions & 5 deletions mono/metadata/threads.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,9 @@ static void self_abort_internal (MonoError *error);
static void async_suspend_internal (MonoInternalThread *thread, gboolean interrupt);
static void self_suspend_internal (void);

static gboolean
mono_thread_set_interruption_requested_flags (MonoInternalThread *thread, gboolean sync);

static MonoException* mono_thread_execute_interruption (void);
static void ref_stack_destroy (gpointer rs);

Expand Down Expand Up @@ -366,6 +369,30 @@ mono_thread_set_interruption_requested (MonoInternalThread *thread)
{
//always force when the current thread is doing it to itself.
gboolean sync = thread == mono_thread_internal_current ();
/* Normally synchronous interruptions can bypass abort protection. */
return mono_thread_set_interruption_requested_flags (thread, sync);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about renaming mono_thread_set_interruption_requested to follow mono_thread_set_self_interruption_respect_abort_prot?

This would allow us to get rid of the weird _flags variant.

}

/* Returns TRUE if there was a state change and the interruption can be
* processed. This variant defers a self abort when inside an abort protected
* block. Normally this should only be done when a thread has received an
* outside indication that it should abort. (For example when the JIT sets a
* flag in an finally block.)
*/

static gboolean
mono_thread_set_self_interruption_respect_abort_prot (void)
{
MonoInternalThread *thread = mono_thread_internal_current ();
/* N.B. Sets the ASYNC_REQUESTED_BIT for current this thread,
* which is unusual. */
return mono_thread_set_interruption_requested_flags (thread, FALSE);
}

/* Returns TRUE if there was a state change and the interruption can be processed. */
static gboolean
mono_thread_set_interruption_requested_flags (MonoInternalThread *thread, gboolean sync)
{
gsize old_state, new_state;
do {
old_state = thread->thread_state;
Expand Down Expand Up @@ -4081,12 +4108,48 @@ mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
return TRUE;
}

/* This is a JIT icall. This icall is called from a finally block when
* mono_install_handler_block_guard called by another thread has flipped the
* finally block's exvar (see mono_find_exvar_for_offset). In that case, if
* the finally is in an abort protected block, we must defer the abort
* exception until we leave the abort protected block. Otherwise we proceed
* with a synchronous self-abort.
*/
void
mono_thread_self_abort (void)
{
ERROR_DECL (error);
self_abort_internal (error);
mono_error_set_pending_exception (error);
ves_icall_thread_finish_async_abort (void)
{
/* We were called from the handler block and are about to
* leave it. (If we end up postponing the abort because we're
* in an abort protected block, the unwinder won't run and
* won't clear the handler block itself which will confuse the
* unwinder if we're in a try {} catch {} and we throw again.
* ie, this:
* static Constructor () {
* try {
* try {
* } finally {
* icall (); // Thread.Abort landed here,
* // and caused the handler block to be installed
* if (exvar)
* ves_icall_thread_finish_async_abort (); // we're here
* }
* throw E ();
* } catch (E) {
* // unwinder will get confused here and synthesize a self abort
* }
* }
*
* More interestingly, this doesn't only happen with icalls - a JIT
* trampoline is native code that will cause a handler to be installed.
* So the above situation can happen with any code in a "finally"
* clause.
*/
mono_get_eh_callbacks ()->mono_uninstall_current_handler_block_guard ();
/* Just set the async interruption requested bit. Rely on the icall
* wrapper of this icall to process the thread interruption, respecting
* any abort protection blocks in our call stack.
*/
mono_thread_set_self_interruption_respect_abort_prot ();
}

/*
Expand Down
2 changes: 1 addition & 1 deletion mono/mini/method-to-ir.c
Original file line number Diff line number Diff line change
Expand Up @@ -11522,7 +11522,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
NEW_BBLOCK (cfg, dont_throw);
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, abort_exc->dreg, 0);
MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
mono_emit_jit_icall (cfg, mono_thread_self_abort, NULL);
mono_emit_jit_icall (cfg, ves_icall_thread_finish_async_abort, NULL);
cfg->cbb->clause_holes = tmp;

MONO_START_BB (cfg, dont_throw);
Expand Down
17 changes: 14 additions & 3 deletions mono/mini/mini-exceptions.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ static void mono_raise_exception_with_ctx (MonoException *exc, MonoContext *ctx)
static void mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data);
static gboolean mono_current_thread_has_handle_block_guard (void);
static gboolean mono_install_handler_block_guard (MonoThreadUnwindState *ctx);
static void mono_uninstall_current_handler_block_guard (void);

static gboolean
first_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer addr)
Expand Down Expand Up @@ -232,6 +233,7 @@ mono_exceptions_init (void)
cbs.mono_raise_exception_with_ctx = mono_raise_exception_with_ctx;
cbs.mono_exception_walk_trace = mono_exception_walk_trace;
cbs.mono_install_handler_block_guard = mono_install_handler_block_guard;
cbs.mono_uninstall_current_handler_block_guard = mono_uninstall_current_handler_block_guard;
cbs.mono_current_thread_has_handle_block_guard = mono_current_thread_has_handle_block_guard;
cbs.mono_clear_abort_threshold = mini_clear_abort_threshold;
cbs.mono_above_abort_threshold = mini_above_abort_threshold;
Expand Down Expand Up @@ -2955,10 +2957,10 @@ install_handler_block_guard (MonoJitInfo *ji, MonoContext *ctx)
break;
}

/*no matching finally */
if (i == ji->num_clauses)
return;
/*no matching finally - can't happen, we parallel the logic in find_last_handler_block. */
g_assert (i < ji->num_clauses);

g_message (" installed handler block guard at %p\n", ip);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

escaped debug line?

/*Load the spvar*/
bp = (guint8*)MONO_CONTEXT_GET_BP (ctx);
*(bp + clause->exvar_offset) = 1;
Expand Down Expand Up @@ -2996,6 +2998,15 @@ mono_install_handler_block_guard (MonoThreadUnwindState *ctx)
return TRUE;
}

static void
mono_uninstall_current_handler_block_guard (void)
{
MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
if (jit_tls)
jit_tls->handler_block = NULL;
}


static gboolean
mono_current_thread_has_handle_block_guard (void)
{
Expand Down
2 changes: 1 addition & 1 deletion mono/mini/mini-runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -4206,7 +4206,7 @@ register_icalls (void)
register_dyn_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
register_dyn_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", "void ptr", TRUE);
register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
register_icall (mono_thread_self_abort, "mono_thread_self_abort", "void", FALSE);
register_icall (ves_icall_thread_finish_async_abort, "ves_icall_thread_finish_async_abort", "void", FALSE);
register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "object", FALSE);
register_icall (mono_thread_force_interruption_checkpoint_noraise, "mono_thread_force_interruption_checkpoint_noraise", "object", FALSE);

Expand Down
1 change: 0 additions & 1 deletion mono/tests/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -970,7 +970,6 @@ CI_PR_DISABLED_TESTS = \

if ENABLE_COOP
CI_PR_DISABLED_TESTS += \
abort-cctor.exe \
bug-58782-plain-throw.exe \
bug-58782-capture-and-throw.exe
endif
Expand Down
58 changes: 58 additions & 0 deletions mono/tests/abort-cctor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

class Driver
{
public static SemaphoreSlim sema1 = new SemaphoreSlim (0);
public static ManualResetEvent mre1 = new ManualResetEvent (false);
public static ManualResetEvent mre2 = new ManualResetEvent (false);

Expand Down Expand Up @@ -367,13 +368,70 @@ static void Test5 ()
Environment.Exit (15);
}

public static bool got_to_the_end_of_outer_finally = false;
public static bool got_to_the_end_of_inner_finally = false;

class StaticConstructor6 {

static StaticConstructor6 ()
{
try {
Setup6 ();
} finally {
Driver.got_to_the_end_of_outer_finally = true;
}
}

[MethodImplAttribute (MethodImplOptions.NoInlining)]
public static void Setup6 () {
try {
} finally {
Driver.sema1.Release ();
Thread.Sleep (1000); /* hopefully we get woken up here */
Driver.got_to_the_end_of_inner_finally = true;
}
}
}

[MethodImplAttribute (MethodImplOptions.NoInlining)]
static void IsStaticConstructor6Viable () {
Console.WriteLine ("IsStaticConstructor6Viable? got to inner finally? {0} got to outer finally? {1}",
Driver.got_to_the_end_of_inner_finally,
Driver.got_to_the_end_of_outer_finally);
new StaticConstructor6 ();
if (!Driver.got_to_the_end_of_inner_finally)
Environment.Exit (17);
if (!Driver.got_to_the_end_of_outer_finally)
Environment.Exit (18);
}

public static void Test6 ()
{
Thread thread = new Thread (() => {
new StaticConstructor6 ();
});

thread.Start ();
Driver.sema1.Wait ();
thread.Abort ();
thread.Join ();
try {
IsStaticConstructor6Viable ();
Console.WriteLine ("StaticConstructor6 is viable");
} catch (TypeInitializationException e) {
Console.WriteLine ("StaticConstructor6 is not viable");
Environment.Exit (19);
}
}

public static int Main ()
{
Test1 ();
Test2 ();
Test3 ();
Test4 ();
Test5 ();
Test6 ();
Console.WriteLine ("done, all things good");
return 0;
}
Expand Down