Skip to content

Commit

Permalink
[2019-08] [debugger][exception] Debugger breaks on handled exceptions (
Browse files Browse the repository at this point in the history
…#17202)

* If there is a perform_wait_callback in the stack there will be another catch generated by the owner thread, so we don't need to throw, we can continue and find the next catch. Fixes #17083

* Reverting unit test changed on commit 405d521.

* Fixing assert when calling mono_jit_info_get_method if it was a trampoline.
  • Loading branch information
monojenkins authored and thaystg committed Oct 7, 2019
1 parent f83c321 commit 77258ea
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 5 deletions.
22 changes: 22 additions & 0 deletions mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,10 @@ public static int Main (String[] args) {
unhandled_exception_wrapper ();
return 0;
}
if (args.Length >0 && args [0] == "unhandled-exception-perform-wait-callback") {
unhandled_exception_perform_wait_callback ();
return 0;
}
if (args.Length >0 && args [0] == "unhandled-exception-endinvoke") {
unhandled_exception_endinvoke ();
return 0;
Expand Down Expand Up @@ -1649,6 +1653,24 @@ public static void unhandled_exception_wrapper () {
public static void unhandled_exception_endinvoke_2 () {
}

[MethodImplAttribute (MethodImplOptions.NoInlining)]
public static void unhandled_exception_perform_wait_callback () {
try
{
var results = ResolveAsync().GetAwaiter().GetResult();
}
catch (SocketException sockEx)
{
//Console.WriteLine("correctly handled");
}
}

public static async Task<List<string>> ResolveAsync()
{
var addresses = await System.Net.Dns.GetHostAddressesAsync("foo.bar.baz");
return new List<string>(addresses.Select(addr => addr.ToString()));
}

[MethodImplAttribute (MethodImplOptions.NoInlining)]
public static void unhandled_exception_endinvoke () {
Action action = new Action (() =>
Expand Down
19 changes: 17 additions & 2 deletions mcs/class/Mono.Debugger.Soft/Test/dtest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4233,8 +4233,6 @@ public void UnhandledException_2 () {
var e = run_until ("unhandled_exception_endinvoke");
vm.Resume ();

var e1 = GetNextEvent (); //this should be the exception
vm.Resume ();
var e2 = GetNextEvent ();
Assert.IsFalse (e2 is ExceptionEvent);

Expand Down Expand Up @@ -4281,6 +4279,23 @@ public void UnhandledException3 () {
vm = null;
}

[Test]
public void UnhandledException4 () {
vm.Exit (0);

Start (dtest_app_path, "unhandled-exception-perform-wait-callback");

var req = vm.CreateExceptionRequest (null, false, true);
req.Enable ();

var e = run_until ("unhandled_exception_perform_wait_callback");
vm.Resume ();

var e2 = GetNextEvent ();
Assert.IsTrue (e2 is VMDeathEvent);
vm = null;
}

[Test]
public void GCWhileSuspended () {
// Check that objects are kept alive during suspensions
Expand Down
19 changes: 16 additions & 3 deletions mono/mini/mini-exceptions.c
Original file line number Diff line number Diff line change
Expand Up @@ -2196,7 +2196,7 @@ typedef enum {
* return \c MONO_FIRST_PASS_CALLBACK_TO_NATIVE).
*/
static MonoFirstPassResult
handle_exception_first_pass (MonoContext *ctx, MonoObject *obj, gint32 *out_filter_idx, MonoJitInfo **out_ji, MonoJitInfo **out_prev_ji, MonoObject *non_exception, StackFrameInfo *catch_frame)
handle_exception_first_pass (MonoContext *ctx, MonoObject *obj, gint32 *out_filter_idx, MonoJitInfo **out_ji, MonoJitInfo **out_prev_ji, MonoObject *non_exception, StackFrameInfo *catch_frame, gboolean *has_perform_wait_callback_method)
{
ERROR_DECL (error);
MonoDomain *domain = mono_domain_get ();
Expand Down Expand Up @@ -2449,6 +2449,17 @@ handle_exception_first_pass (MonoContext *ctx, MonoObject *obj, gint32 *out_filt
frame.native_offset = (char*)ei->handler_start - (char*)ji->code_start;
*catch_frame = frame;
result = MONO_FIRST_PASS_HANDLED;
if (method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) {
//try to find threadpool_perform_wait_callback_method
unwind_res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, &new_ctx, &new_ctx, NULL, &lmf, NULL, &frame);
while (unwind_res) {
if (frame.ji && !frame.ji->is_trampoline && jinfo_get_method (frame.ji) == mono_defaults.threadpool_perform_wait_callback_method) {
*has_perform_wait_callback_method = TRUE;
break;
}
unwind_res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, &new_ctx, &new_ctx, NULL, &lmf, NULL, &frame);
}
}
return result;
}
mono_error_cleanup (isinst_error);
Expand Down Expand Up @@ -2653,7 +2664,8 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu

StackFrameInfo catch_frame;
MonoFirstPassResult res;
res = handle_exception_first_pass (&ctx_cp, obj, &first_filter_idx, &ji, &prev_ji, non_exception, &catch_frame);
gboolean has_perform_wait_callback_method = FALSE;
res = handle_exception_first_pass (&ctx_cp, obj, &first_filter_idx, &ji, &prev_ji, non_exception, &catch_frame, &has_perform_wait_callback_method);

if (res == MONO_FIRST_PASS_UNHANDLED) {
if (mono_aot_mode == MONO_AOT_MODE_LLVMONLY_INTERP) {
Expand Down Expand Up @@ -2693,7 +2705,8 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu
if (unhandled)
mini_get_dbg_callbacks ()->handle_exception ((MonoException *)obj, ctx, NULL, NULL);
else if (!ji || (jinfo_get_method (ji)->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE)) {
mini_get_dbg_callbacks ()->handle_exception ((MonoException *)obj, ctx, NULL, NULL);
if (!has_perform_wait_callback_method)
mini_get_dbg_callbacks ()->handle_exception ((MonoException *)obj, ctx, NULL, NULL);
mini_get_dbg_callbacks ()->handle_exception ((MonoException *)obj, ctx, &ctx_cp, &catch_frame);
}
else if (res != MONO_FIRST_PASS_CALLBACK_TO_NATIVE)
Expand Down

0 comments on commit 77258ea

Please sign in to comment.