[runtime] Handle native size of structs with explicit layout and min alignment smalle...
authorRodrigo Kumpera <kumpera@gmail.com>
Wed, 22 Jan 2014 21:43:08 +0000 (16:43 -0500)
committerRodrigo Kumpera <kumpera@gmail.com>
Wed, 22 Jan 2014 21:51:50 +0000 (16:51 -0500)
The calculating the native size of structs with explicit layout we need to take into consideration the minimum alignment
needed and the packing asked.

If no packing is supplied, we should respect the minimum alignment. If packing is supplied we should use the minimum required.

mono/metadata/marshal.c
mono/tests/marshal7.cs

index fa50598f7d72c68a36f2b4396988c2f24a6b61ba..9aa3badf700549cec88283e8257d9b08ac26a258 100644 (file)
@@ -12290,7 +12290,7 @@ mono_marshal_load_type_info (MonoClass* klass)
                case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT:
                        size = mono_marshal_type_size (field->type, info->fields [j].mspec, 
                                                       &align, TRUE, klass->unicode);
-                       min_align = packing;
+                       min_align = MAX (align, min_align);
                        info->fields [j].offset = field->offset - sizeof (MonoObject);
                        info->native_size = MAX (info->native_size, info->fields [j].offset + size);
                        break;
@@ -12304,9 +12304,12 @@ mono_marshal_load_type_info (MonoClass* klass)
                 * If the provided Size is equal or larger than the calculated size, and there
                 * was no Pack attribute, we set min_align to 1 to avoid native_size being increased
                 */
-               if (layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT)
+               if (layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
                        if (native_size && native_size == info->native_size && klass->packing_size == 0)
                                min_align = 1;
+                       else
+                               min_align = MIN (min_align, packing);
+               }
        }
 
        if (info->native_size & (min_align - 1)) {
index aeb7b55c873d1eb2d7a46f152a9166c18463087d..02cfbbd40a6cacef016398732a3dc4323c730413 100644 (file)
@@ -1,4 +1,5 @@
 using System;
+using System.Reflection;
 using System.Runtime.InteropServices;
 
 public class Test 
@@ -51,7 +52,8 @@ public class Test
                object itf;
        }
 
-       // Size should be 12 in both 32 and 64 bits
+       // Size should be 16 in both 32 and 64 bits win/linux
+       // Size should be 12 on 32bits OSX size alignment of long is 4
        [StructLayout (LayoutKind.Explicit)]
        struct TestStruct8 {
                [FieldOffset (0)]
@@ -69,7 +71,8 @@ public class Test
                public ulong b;
        }
 
-       // Size should be 11 in both 32 and 64 bits
+       // Size should be 16 in both 32 and 64 bits
+       // Size should be 12 on 32bits OSX size alignment of long is 4
        [StructLayout (LayoutKind.Explicit)]
        struct TestStruct10 {
                [FieldOffset (0)]
@@ -95,6 +98,34 @@ public class Test
                public int b;
        }
 
+       // Size should always be 12, since pack = 0, size = 0 and min alignment = 4
+       //When pack is not set, we default to 8, so min (8, min alignment) -> 4
+       [StructLayout (LayoutKind.Explicit)]
+       struct TestStruct13 {
+               [FieldOffset(0)]
+               int one;
+               [FieldOffset(4)]
+               int two;
+               [FieldOffset(8)]
+               int three;
+       }
+
+       // Size should always be 12, since pack = 8, size = 0 and min alignment = 4
+       //It's aligned to min (pack, min alignment) -> 4
+       [StructLayout (LayoutKind.Explicit)]
+       struct TestStruct14 {
+               [FieldOffset(0)]
+               int one;
+               [FieldOffset(4)]
+               int two;
+               [FieldOffset(8)]
+               int three;
+       }
+       static bool IsOSX ()
+       {
+               return (int)typeof (Environment).GetMethod ("get_Platform", BindingFlags.Static | BindingFlags.NonPublic).Invoke (null, null) == 6;
+       }
+
        public unsafe static int Main () 
        {
                ///
@@ -181,16 +212,27 @@ public class Test
                // a VARIANT is 
                if (Marshal.SizeOf (typeof (TestStruct7)) != 16)
                        return 13;
-               if (Marshal.SizeOf (typeof (TestStruct8)) != 16)
-                       return 14;
+               if (IsOSX () && IntPtr.Size == 4) {
+                       if (Marshal.SizeOf (typeof (TestStruct8)) != 12)
+                               return 14;
+                       if (Marshal.SizeOf (typeof (TestStruct10)) != 12)
+                               return 16;
+               } else {
+                       if (Marshal.SizeOf (typeof (TestStruct8)) != 16)
+                               return 14;
+                       if (Marshal.SizeOf (typeof (TestStruct10)) != 16)
+                               return 16;
+               }
                if (Marshal.SizeOf (typeof (TestStruct9)) != 12)
                        return 15;
-               if (Marshal.SizeOf (typeof (TestStruct10)) != 16)
-                       return 16;
                if (Marshal.SizeOf (typeof (TestStruct11)) != 11)
                        return 17;
                if (Marshal.SizeOf (typeof (TestStruct12)) != 6)
                        return 18;
+               if (Marshal.SizeOf (typeof (TestStruct13)) != 12)
+                       return 19;
+               if (Marshal.SizeOf (typeof (TestStruct14)) != 12)
+                       return 20;
                return 0;
        }
 }