[sdb] Fix round tripping of vtypes with boxed fields. Fixes #12354.
authorZoltan Varga <vargaz@gmail.com>
Sun, 28 Jul 2013 07:40:32 +0000 (09:40 +0200)
committerZoltan Varga <vargaz@gmail.com>
Sun, 28 Jul 2013 07:40:32 +0000 (09:40 +0200)
mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs
mcs/class/Mono.Debugger.Soft/Test/dtest.cs
mono/mini/debugger-agent.c

index 26c45e10d5b800b874b5f6aafcf5f62f1e1937a2..241f7d070e3de2c38d0c4ba98fa520c1edf7a72e 100644 (file)
@@ -193,6 +193,7 @@ public class Tests : TestsBase
        public AStruct field_struct;
        public object field_boxed_struct;
        public GStruct<int> generic_field_struct;
+       public KeyValuePair<int, object> boxed_struct_field;
        [ThreadStatic]
        public static int tls_i;
        public static bool is_attached = Debugger.IsAttached;
@@ -498,7 +499,7 @@ public class Tests : TestsBase
        }
 
        public static void vtypes () {
-               Tests t = new Tests () { field_struct = new AStruct () { i = 42, s = "S", k = 43 }, generic_field_struct = new GStruct<int> () { i = 42 }, field_boxed_struct = new AStruct () { i = 42 }};
+               Tests t = new Tests () { field_struct = new AStruct () { i = 42, s = "S", k = 43 }, generic_field_struct = new GStruct<int> () { i = 42 }, field_boxed_struct = new AStruct () { i = 42 }, boxed_struct_field = new KeyValuePair<int, object> (1, (long)42 ) };
                AStruct s = new AStruct { i = 44, s = "T", k = 45 };
                AStruct[] arr = new AStruct[] { 
                        new AStruct () { i = 1, s = "S1" },
index 210dd89b0e03bbdb65b289a130d85b9a819b0cff..d549c0ba6faf0e7cab4c4124d1d432356bb7ff20 100644 (file)
@@ -1335,6 +1335,17 @@ public class DebuggerTests
                Assert.AreEqual ("AStruct", s.Type.Name);
                AssertValue (42, s ["i"]);
 
+               // Check round tripping of boxed struct fields (#12354)
+               obj = o.GetValue (o.Type.GetField ("boxed_struct_field"));
+               o.SetValue (o.Type.GetField ("boxed_struct_field"), obj);
+               obj = o.GetValue (o.Type.GetField ("boxed_struct_field"));
+               s = obj as StructMirror;
+               AssertValue (1, s ["key"]);
+               obj = s ["value"];
+               Assert.IsTrue (obj is StructMirror);
+               s = obj as StructMirror;
+               AssertValue (42, s ["m_value"]);
+
                // vtypes as arguments
                s = frame.GetArgument (0) as StructMirror;
                AssertValue (44, s ["i"]);
index b01aa722d4211ed2178ecc845658ef2051ff7a87..ebf7735578575cfda26e0b514b6960322c38e463 100644 (file)
@@ -5589,6 +5589,49 @@ obj_is_of_type (MonoObject *obj, MonoType *t)
 static ErrorCode
 decode_value (MonoType *t, MonoDomain *domain, guint8 *addr, guint8 *buf, guint8 **endbuf, guint8 *limit);
 
+static ErrorCode
+decode_vtype (MonoType *t, MonoDomain *domain, guint8 *addr, guint8 *buf, guint8 **endbuf, guint8 *limit)
+{
+       gboolean is_enum;
+       MonoClass *klass;
+       MonoClassField *f;
+       int nfields;
+       gpointer iter = NULL;
+       MonoDomain *d;
+       int err;
+
+       is_enum = decode_byte (buf, &buf, limit);
+       /* Enums are sent as a normal vtype */
+       if (is_enum)
+               return ERR_NOT_IMPLEMENTED;
+       klass = decode_typeid (buf, &buf, limit, &d, &err);
+       if (err)
+               return err;
+
+       if (t && klass != mono_class_from_mono_type (t)) {
+               char *name = mono_type_full_name (t);
+               char *name2 = mono_type_full_name (&klass->byval_arg);
+               DEBUG(1, fprintf (log_file, "[%p] Expected value of type %s, got %s.\n", (gpointer)GetCurrentThreadId (), name, name2));
+               g_free (name);
+               g_free (name2);
+               return ERR_INVALID_ARGUMENT;
+       }
+
+       nfields = decode_int (buf, &buf, limit);
+       while ((f = mono_class_get_fields (klass, &iter))) {
+               if (f->type->attrs & FIELD_ATTRIBUTE_STATIC)
+                       continue;
+               if (mono_field_is_deleted (f))
+                       continue;
+               err = decode_value (f->type, domain, (guint8*)addr + f->offset - sizeof (MonoObject), buf, &buf, limit);
+               if (err)
+                       return err;
+               nfields --;
+       }
+       g_assert (nfields == 0);
+       return 0;
+}
+
 static ErrorCode
 decode_value_internal (MonoType *t, int type, MonoDomain *domain, guint8 *addr, guint8 *buf, guint8 **endbuf, guint8 *limit)
 {
@@ -5661,38 +5704,11 @@ decode_value_internal (MonoType *t, int type, MonoDomain *domain, guint8 *addr,
                g_assert (type == MONO_TYPE_VALUETYPE);
                /* Fall through */
                handle_vtype:
-       case MONO_TYPE_VALUETYPE: {
-               gboolean is_enum = decode_byte (buf, &buf, limit);
-               MonoClass *klass;
-               MonoClassField *f;
-               int nfields;
-               gpointer iter = NULL;
-               MonoDomain *d;
-
-               /* Enums are sent as a normal vtype */
-               if (is_enum)
-                       return ERR_NOT_IMPLEMENTED;
-               klass = decode_typeid (buf, &buf, limit, &d, &err);
+       case MONO_TYPE_VALUETYPE:
+               err = decode_vtype (t, domain, addr,buf, &buf, limit);
                if (err)
                        return err;
-
-               if (klass != mono_class_from_mono_type (t))
-                       return ERR_INVALID_ARGUMENT;
-
-               nfields = decode_int (buf, &buf, limit);
-               while ((f = mono_class_get_fields (klass, &iter))) {
-                       if (f->type->attrs & FIELD_ATTRIBUTE_STATIC)
-                               continue;
-                       if (mono_field_is_deleted (f))
-                               continue;
-                       err = decode_value (f->type, domain, (guint8*)addr + f->offset - sizeof (MonoObject), buf, &buf, limit);
-                       if (err)
-                               return err;
-                       nfields --;
-               }
-               g_assert (nfields == 0);
                break;
-       }
        handle_ref:
        default:
                if (MONO_TYPE_IS_REFERENCE (t)) {
@@ -5717,7 +5733,44 @@ decode_value_internal (MonoType *t, int type, MonoDomain *domain, guint8 *addr,
                                mono_gc_wbarrier_generic_store (addr, obj);
                        } else if (type == VALUE_TYPE_ID_NULL) {
                                *(MonoObject**)addr = NULL;
+                       } else if (type == MONO_TYPE_VALUETYPE) {
+                               guint8 *buf2;
+                               gboolean is_enum;
+                               MonoClass *klass;
+                               MonoDomain *d;
+                               guint8 *vtype_buf;
+                               int vtype_buf_size;
+
+                               /* This can happen when round-tripping boxed vtypes */
+                               /*
+                                * Obtain vtype class.
+                                * Same as the beginning of the handle_vtype case above.
+                                */
+                               buf2 = buf;
+                               is_enum = decode_byte (buf, &buf, limit);
+                               if (is_enum)
+                                       return ERR_NOT_IMPLEMENTED;
+                               klass = decode_typeid (buf, &buf, limit, &d, &err);
+                               if (err)
+                                       return err;
+
+                               /* Decode the vtype into a temporary buffer, then box it. */
+                               vtype_buf_size = mono_class_value_size (klass, NULL);
+                               vtype_buf = g_malloc0 (vtype_buf_size);
+                               g_assert (vtype_buf);
+
+                               buf = buf2;
+                               err = decode_vtype (NULL, domain, vtype_buf, buf, &buf, limit);
+                               if (err) {
+                                       g_free (vtype_buf);
+                                       return err;
+                               }
+                               *(MonoObject**)addr = mono_value_box (d, klass, vtype_buf);
+                               g_free (vtype_buf);
                        } else {
+                               char *name = mono_type_full_name (t);
+                               DEBUG(1, fprintf (log_file, "[%p] Expected value of type %s, got 0x%0x.\n", (gpointer)GetCurrentThreadId (), name, type));
+                               g_free (name);
                                return ERR_INVALID_ARGUMENT;
                        }
                } else {
@@ -6109,8 +6162,10 @@ do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke, guint8
        if (m->klass->valuetype && (m->flags & METHOD_ATTRIBUTE_STATIC)) {
                /* Should be null */
                int type = decode_byte (p, &p, end);
-               if (type != VALUE_TYPE_ID_NULL)
+               if (type != VALUE_TYPE_ID_NULL) {
+                       DEBUG (1, fprintf (log_file, "[%p] Error: Static vtype method invoked with this argument.\n", (gpointer)GetCurrentThreadId ()));
                        return ERR_INVALID_ARGUMENT;
+               }
                memset (this_buf, 0, mono_class_instance_size (m->klass));
        } else {
                err = decode_value (&m->klass->byval_arg, domain, this_buf, p, &p, end);
@@ -6354,7 +6409,7 @@ invoke_method (void)
                tls->resume_count -= invoke->suspend_count;
        }
 
-       DEBUG (1, fprintf (log_file, "[%p] Invoke finished, resume_count = %d.\n", (gpointer)GetCurrentThreadId (), tls->resume_count));
+       DEBUG (1, fprintf (log_file, "[%p] Invoke finished (%d), resume_count = %d.\n", (gpointer)GetCurrentThreadId (), err, tls->resume_count));
 
        /*
         * Take the loader lock to avoid race conditions with CMD_VM_ABORT_INVOKE: