Skip to content

Commit

Permalink
[debugger] Assert when async debug a generic method (#17727)
Browse files Browse the repository at this point in the history
* When we try to call a method to get the async_id to do an async debug and we are trying to do this in a generic method like this:

async Task<T> ExecuteAsync_Broken<T>()
 {
            await Task.Delay(2);
            return default;
  }

We need to inflate the generic type before call the method or we will get the error:  Could not execute the method because the containing type 'System.Runtime.CompilerServices.AsyncTaskMethodBuilder1[T_REF]’, is not fully instantiated.

Fixes #17549
Fixes #17569
  • Loading branch information
thaystg committed Nov 13, 2019
1 parent fe0f824 commit dd18ec4
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 9 deletions.
12 changes: 12 additions & 0 deletions mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,7 @@ public static void wait_one ()
if_property_stepping();
fixed_size_array();
test_new_exception_filter();
test_async_debug_generics();
return 3;
}

Expand Down Expand Up @@ -903,6 +904,17 @@ public static void ss7_3 ()
}
}

[MethodImplAttribute (MethodImplOptions.NoInlining)]
public static void test_async_debug_generics () {
ExecuteAsync_Broken<object>().Wait ();
}

async static Task<T> ExecuteAsync_Broken<T>()
{
await Task.Delay(2);
return default;
}

[MethodImplAttribute (MethodImplOptions.NoInlining)]
public static void inspect_enumerator_in_generic_struct() {
TestEnumeratorInsideGenericStruct<String, String> generic_struct = new TestEnumeratorInsideGenericStruct<String, String>(new KeyValuePair<string, string>("0", "f1"));
Expand Down
10 changes: 10 additions & 0 deletions mcs/class/Mono.Debugger.Soft/Test/dtest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5152,6 +5152,16 @@ public void Bug59649 ()
vm = null;
}

[Test]
public void TestAsyncDebugGenerics () {
Event e = run_until ("test_async_debug_generics");
e = step_in_await ("test_async_debug_generics", e);
e = step_in_await ("MoveNext", e);
e = step_in_await ("MoveNext", e);
e = step_in_await ("MoveNext", e);
e = step_in_await ("MoveNext", e);
}

#endif
} // class DebuggerTests
} // namespace
35 changes: 31 additions & 4 deletions mono/mini/debugger-agent.c
Original file line number Diff line number Diff line change
Expand Up @@ -4526,6 +4526,31 @@ get_object_id_for_debugger_method (MonoClass* async_builder_class)
return method;
}

static MonoClass *
get_class_to_get_builder_field(DbgEngineStackFrame *frame)
{
ERROR_DECL (error);
gpointer this_addr = get_this_addr (frame);
MonoClass *original_class = frame->method->klass;
MonoClass *ret;
if (!m_class_is_valuetype (original_class) && mono_class_is_open_constructed_type (m_class_get_byval_arg (original_class))) {
MonoObject *this_obj = *(MonoObject**)this_addr;
MonoGenericContext context;
MonoType *inflated_type;

g_assert (this_obj);
context = mono_get_generic_context_from_stack_frame (frame->ji, this_obj->vtable);
inflated_type = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (original_class), &context, error);
mono_error_assert_ok (error); /* FIXME don't swallow the error */

ret = mono_class_from_mono_type_internal (inflated_type);
mono_metadata_free_type (inflated_type);
return ret;
}
return original_class;
}


/* Return the address of the AsyncMethodBuilder struct belonging to the state machine method pointed to by FRAME */
static gpointer
get_async_method_builder (DbgEngineStackFrame *frame)
Expand All @@ -4534,15 +4559,17 @@ get_async_method_builder (DbgEngineStackFrame *frame)
MonoClassField *builder_field;
gpointer builder;
gpointer this_addr;
MonoClass* klass = frame->method->klass;

builder_field = mono_class_get_field_from_name_full (frame->method->klass, "<>t__builder", NULL);
klass = get_class_to_get_builder_field(frame);
builder_field = mono_class_get_field_from_name_full (klass, "<>t__builder", NULL);
g_assert (builder_field);

this_addr = get_this_addr (frame);
if (!this_addr)
return NULL;

if (m_class_is_valuetype (frame->method->klass)) {
if (m_class_is_valuetype (klass)) {
builder = mono_vtype_get_field_addr (*(guint8**)this_addr, builder_field);
} else {
this_obj = *(MonoObject**)this_addr;
Expand Down Expand Up @@ -4574,7 +4601,7 @@ get_this_async_id (DbgEngineStackFrame *frame)
if (!builder)
return 0;

builder_field = mono_class_get_field_from_name_full (frame->method->klass, "<>t__builder", NULL);
builder_field = mono_class_get_field_from_name_full (get_class_to_get_builder_field(frame), "<>t__builder", NULL);
g_assert (builder_field);

tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
Expand All @@ -4598,7 +4625,7 @@ get_this_async_id (DbgEngineStackFrame *frame)
static gboolean
set_set_notification_for_wait_completion_flag (DbgEngineStackFrame *frame)
{
MonoClassField *builder_field = mono_class_get_field_from_name_full (frame->method->klass, "<>t__builder", NULL);
MonoClassField *builder_field = mono_class_get_field_from_name_full (get_class_to_get_builder_field(frame), "<>t__builder", NULL);
g_assert (builder_field);
gpointer builder = get_async_method_builder (frame);
g_assert (builder);
Expand Down
12 changes: 7 additions & 5 deletions mono/mini/mini-exceptions.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
#include "mini.h"
#include "trace.h"
#include "debugger-agent.h"
#include "debugger-engine.h"
#include "seq-points.h"
#include "llvm-runtime.h"
#include "mini-llvm.h"
Expand Down Expand Up @@ -843,8 +844,8 @@ get_generic_info_from_stack_frame (MonoJitInfo *ji, MonoContext *ctx)
/*
* generic_info is either a MonoMethodRuntimeGenericContext or a MonoVTable.
*/
static MonoGenericContext
get_generic_context_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
MonoGenericContext
mono_get_generic_context_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
{
MonoGenericContext context = { NULL, NULL };
MonoClass *klass, *method_container_class;
Expand Down Expand Up @@ -889,6 +890,7 @@ get_generic_context_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
return context;
}


static MonoMethod*
get_method_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
{
Expand All @@ -898,7 +900,7 @@ get_method_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)

if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this)
return jinfo_get_method (ji);
context = get_generic_context_from_stack_frame (ji, generic_info);
context = mono_get_generic_context_from_stack_frame (ji, generic_info);

method = jinfo_get_method (ji);
method = mono_method_get_declaring_generic_method (method);
Expand Down Expand Up @@ -1949,7 +1951,7 @@ get_exception_catch_class (MonoJitExceptionInfo *ei, MonoJitInfo *ji, MonoContex

if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this)
return catch_class;
context = get_generic_context_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, ctx));
context = mono_get_generic_context_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, ctx));

/* FIXME: we shouldn't inflate but instead put the
type in the rgctx and fetch it from there. It
Expand Down Expand Up @@ -4020,7 +4022,7 @@ mono_llvm_match_exception (MonoJitInfo *jinfo, guint32 region_start, guint32 reg
MonoType *inflated_type;

g_assert (rgctx || this_obj);
context = get_generic_context_from_stack_frame (jinfo, rgctx ? rgctx : this_obj->vtable);
context = mono_get_generic_context_from_stack_frame (jinfo, rgctx ? rgctx : this_obj->vtable);
inflated_type = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (catch_class), &context, error);
mono_error_assert_ok (error); /* FIXME don't swallow the error */

Expand Down
3 changes: 3 additions & 0 deletions mono/mini/mini.h
Original file line number Diff line number Diff line change
Expand Up @@ -2909,4 +2909,7 @@ mini_safepoints_enabled (void)
gpointer
mono_arch_load_function (MonoJitICallId jit_icall_id);

MonoGenericContext
mono_get_generic_context_from_stack_frame (MonoJitInfo *ji, gpointer generic_info);

#endif /* __MONO_MINI_H__ */

0 comments on commit dd18ec4

Please sign in to comment.