From 5266e6a8f107d9b91a6073e4fd1ef4eb1ac7ac6d Mon Sep 17 00:00:00 2001 From: Thays Grazia Date: Tue, 15 Jan 2019 15:23:01 -0200 Subject: [2018-08][debugger][backport] Fix crash when there is a generic struct with a field that is an enumerator (#12410) * [Debugger] Fix crash when there is a generic struct with a field that is an enumerator. (#12368) * [Debugger] Debugger crashes when inside a class, there is an internal struct, with a field that is an enumerator. files.myBucket.GetEnumerator().get_Current().Key Fixes #10735 * [Debugger] Debugger crashes when there is a generic struct with a field that is an enumerator. Example: files.get_Current().Key A unit test that reproduces this crash was added too. Fixes #10735 * Removing the extra space. * Merging changes from dtest-app.cs * Adding extra line. --- mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs | 31 ++++++++++++++++++++++++++ mcs/class/Mono.Debugger.Soft/Test/dtest.cs | 19 ++++++++++++++++ mono/mini/debugger-agent.c | 6 +++++ 3 files changed, 56 insertions(+) diff --git a/mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs b/mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs index f0a9ce8dbe6..6da9419e93d 100644 --- a/mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs +++ b/mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs @@ -85,6 +85,31 @@ public class Tests2 { } } +public struct TestEnumeratorInsideGenericStruct +{ + private KeyValuePair _bucket; + private Position _currentPosition; + internal TestEnumeratorInsideGenericStruct(KeyValuePair bucket) + { + _bucket = bucket; + _currentPosition = Position.BeforeFirst; + } + + public KeyValuePair Current + { + get + { + if (_currentPosition == Position.BeforeFirst) + return _bucket; + return _bucket; + } + } + private enum Position + { + BeforeFirst + } +} + public struct AStruct : ITest2 { public int i; public string s; @@ -384,6 +409,7 @@ public class Tests : TestsBase, ITest2 new Tests ().invoke_abort (); new Tests ().evaluate_method (); Bug59649 (); + inspect_enumerator_in_generic_struct(); return 3; } @@ -576,6 +602,11 @@ public class Tests : TestsBase, ITest2 ss_nested_with_two_args(ss_nested_arg (), ss_nested_arg ()); } + [MethodImplAttribute (MethodImplOptions.NoInlining)] + public static void inspect_enumerator_in_generic_struct() { + TestEnumeratorInsideGenericStruct generic_struct = new TestEnumeratorInsideGenericStruct(new KeyValuePair("0", "f1")); + } + [MethodImplAttribute (MethodImplOptions.NoInlining)] public static int ss_nested_with_two_args (int a1, int a2) { return a1 + a2; diff --git a/mcs/class/Mono.Debugger.Soft/Test/dtest.cs b/mcs/class/Mono.Debugger.Soft/Test/dtest.cs index 7de7a22a0ef..a57e5956798 100644 --- a/mcs/class/Mono.Debugger.Soft/Test/dtest.cs +++ b/mcs/class/Mono.Debugger.Soft/Test/dtest.cs @@ -4461,6 +4461,25 @@ public class DebuggerTests assert_location(e, "ss_nested_arg"); } + [Test] + public void InspectEnumeratorInGenericStruct() { + //files.myBucket.GetEnumerator().get_Current().Key watching this generates an exception in Debugger + Event e = run_until("inspect_enumerator_in_generic_struct"); + var req = create_step(e); + req.Enable(); + e = step_once(); + e = step_over(); + StackFrame frame = e.Thread.GetFrames () [0]; + var ginst = frame.Method.GetLocal ("generic_struct"); + Value variable = frame.GetValue (ginst); + StructMirror thisObj = (StructMirror)variable; + TypeMirror thisType = thisObj.Type; + variable = thisObj.InvokeMethod(e.Thread, thisType.GetMethod("get_Current"), null); + thisObj = (StructMirror)variable; + thisType = thisObj.Type; + AssertValue ("f1", thisObj["value"]); + } + [Test] // Uses a fixed port [Category("NotWorking")] diff --git a/mono/mini/debugger-agent.c b/mono/mini/debugger-agent.c index c595475b79f..ab6ba342095 100644 --- a/mono/mini/debugger-agent.c +++ b/mono/mini/debugger-agent.c @@ -5510,6 +5510,12 @@ decode_value_internal (MonoType *t, int type, MonoDomain *domain, guint8 *addr, g_free (name); return ERR_INVALID_ARGUMENT; } + } else if ((t->type == MONO_TYPE_GENERICINST) && + mono_metadata_generic_class_is_valuetype (t->data.generic_class) && + m_class_is_enumtype (t->data.generic_class->container_class)){ + err = decode_vtype (t, domain, addr, buf, &buf, limit); + if (err != ERR_NONE) + return err; } else { NOT_IMPLEMENTED; } -- cgit v1.2.3