[release/8.0] [Mono] Fix offset calculation for nested struct, when pinvoke is enable...
authorgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Fri, 1 Sep 2023 18:24:29 +0000 (12:24 -0600)
committerGitHub <noreply@github.com>
Fri, 1 Sep 2023 18:24:29 +0000 (12:24 -0600)
* Fix offset calculation for nested struct

* Add a test for nested struct with pinvoke

* Move and update test with real c++ implementation

* Exclude newly added test from wasm

* Disable interop tests on android and apple devices

---------

Co-authored-by: Fan Yang <yangfan@microsoft.com>
src/mono/mono/mini/mini-amd64.c
src/tests/Interop/StructMarshalling/PInvoke/GameControllerButtonBind.cs [new file with mode: 0644]
src/tests/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.cpp
src/tests/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.h
src/tests/Interop/StructMarshalling/PInvoke/NestedStruct.cs [new file with mode: 0644]
src/tests/Interop/StructMarshalling/PInvoke/NestedStruct.csproj [new file with mode: 0644]
src/tests/issues.targets

index 1a2f9ff..e03b142 100644 (file)
@@ -357,7 +357,7 @@ collect_field_info_nested (MonoClass *klass, GArray *fields_array, int offset, g
                g_assert(info);
                for (guint32 i = 0; i < info->num_fields; ++i) {
                        if (MONO_TYPE_ISSTRUCT (info->fields [i].field->type)) {
-                               collect_field_info_nested (mono_class_from_mono_type_internal (info->fields [i].field->type), fields_array, info->fields [i].offset, pinvoke, unicode);
+                               collect_field_info_nested (mono_class_from_mono_type_internal (info->fields [i].field->type), fields_array, (offset + info->fields [i].offset), pinvoke, unicode);
                        } else {
                                guint32 align;
                                StructFieldInfo f;
@@ -367,7 +367,7 @@ collect_field_info_nested (MonoClass *klass, GArray *fields_array, int offset, g
                                                                                                                           info->fields [i].mspec,
                                                                                                                           &align, TRUE, unicode);
                                f.offset = offset + info->fields [i].offset;
-                               if (i == info->num_fields - 1 && f.size + f.offset < info->native_size) {
+                               if ((i == info->num_fields - 1) && ((f.size + f.offset) < info->native_size)) {
                                        /* This can happen with .pack directives eg. 'fixed' arrays */
                                        if (MONO_TYPE_IS_PRIMITIVE (f.type)) {
                                                /* Replicate the last field to fill out the remaining place, since the code in add_valuetype () needs type information */
diff --git a/src/tests/Interop/StructMarshalling/PInvoke/GameControllerButtonBind.cs b/src/tests/Interop/StructMarshalling/PInvoke/GameControllerButtonBind.cs
new file mode 100644 (file)
index 0000000..a65994f
--- /dev/null
@@ -0,0 +1,63 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+using System.Text;
+
+public unsafe partial struct GameControllerButtonBind
+{
+    public GameControllerButtonBind
+    (
+        GameControllerBindType? bindType = null,
+        GameControllerButtonBindValue? value = null
+    ) : this()
+    {
+        if (bindType is not null)
+        {
+            BindType = bindType.Value;
+        }
+
+        if (value is not null)
+        {
+            Value = value.Value;
+        }
+    }
+
+    public GameControllerBindType BindType;
+
+    public GameControllerButtonBindValue Value;
+}
+
+public enum GameControllerBindType : int
+{
+    ControllerBindtypeNone = 0x0,
+    ControllerBindtypeButton = 0x1,
+    ControllerBindtypeAxis = 0x2,
+    ControllerBindtypeHat = 0x3,
+    None = 0x0,
+    Button = 0x1,
+    Axis = 0x2,
+    Hat = 0x3,
+}
+
+[StructLayout(LayoutKind.Explicit)]
+public unsafe partial struct GameControllerButtonBindValue
+{
+    [FieldOffset(0)]
+    public int Button;
+
+    [FieldOffset(0)]
+    public int Axis;
+
+    [FieldOffset(0)]
+    public GameControllerButtonBindValueHat Hat;
+}
+
+public unsafe partial struct GameControllerButtonBindValueHat
+{
+    public int Hat;
+
+    public int HatMask;
+}
index 9278650..e19eec7 100644 (file)
@@ -1297,3 +1297,8 @@ extern "C" DLL_EXPORT Int32CLongStruct STDMETHODCALLTYPE AddCLongs(Int32CLongStr
 {
     return { lhs.i + rhs.i, lhs.l + rhs.l };
 }
+
+extern "C" DLL_EXPORT SDL_GameControllerBindType STDMETHODCALLTYPE getBindType(SDL_GameControllerButtonBind button)
+{
+    return button.bindType;
+}
index c85b1e6..17844b8 100644 (file)
@@ -974,3 +974,26 @@ struct Int32CLongStruct
     int32_t i;
     long l;
 };
+
+typedef enum
+{
+    SDL_CONTROLLER_BINDTYPE_NONE = 0,
+    SDL_CONTROLLER_BINDTYPE_BUTTON,
+    SDL_CONTROLLER_BINDTYPE_AXIS,
+    SDL_CONTROLLER_BINDTYPE_HAT
+} SDL_GameControllerBindType;
+
+typedef struct SDL_GameControllerButtonBind
+{
+    SDL_GameControllerBindType bindType;
+    union
+    {
+        int button;
+        int axis;
+        struct {
+            int hat;
+            int hat_mask;
+        } hat;
+    } value;
+
+} SDL_GameControllerButtonBind;
diff --git a/src/tests/Interop/StructMarshalling/PInvoke/NestedStruct.cs b/src/tests/Interop/StructMarshalling/PInvoke/NestedStruct.cs
new file mode 100644 (file)
index 0000000..870e75b
--- /dev/null
@@ -0,0 +1,27 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Runtime.InteropServices;
+using Xunit;
+
+public class Managed
+{
+    [DllImport("MarshalStructAsParam")]
+    static extern GameControllerBindType getBindType (GameControllerButtonBind button);
+
+    public static int Main()
+    {
+        GameControllerButtonBind button = new GameControllerButtonBind(GameControllerBindType.ControllerBindtypeAxis, null);
+        if (getBindType(button) == GameControllerBindType.ControllerBindtypeAxis)
+        {
+            Console.WriteLine("\nTEST PASSED!");
+            return 100;
+        }
+        else
+        {
+            Console.WriteLine("\nTEST FAILED!");
+            return 1;
+        }
+    }
+}
diff --git a/src/tests/Interop/StructMarshalling/PInvoke/NestedStruct.csproj b/src/tests/Interop/StructMarshalling/PInvoke/NestedStruct.csproj
new file mode 100644 (file)
index 0000000..0b0d4aa
--- /dev/null
@@ -0,0 +1,14 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>exe</OutputType>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="NestedStruct.cs" />
+    <Compile Include="GameControllerButtonBind.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(TestSourceDir)Common/CoreCLRTestLibrary/CoreCLRTestLibrary.csproj" />
+    <CMakeProjectReference Include="CMakeLists.txt" />
+  </ItemGroup>
+</Project>
index e9485d2..7ec7dc7 100644 (file)
         <ExcludeList Include="$(XunitTestBinBase)/Interop/PInvoke/SetLastError/**">
             <Issue>https://github.com/dotnet/runtime/issues/64127</Issue>
         </ExcludeList>
+        <ExcludeList Include="$(XunitTestBinBase)/Interop/StructMarshalling/PInvoke/NestedStruct/**">
+            <Issue>https://github.com/dotnet/runtime/issues/64127</Issue>
+        </ExcludeList>
         <ExcludeList Include = "$(XunitTestBinBase)/Interop/SuppressGCTransition/SuppressGCTransitionTest/**">
             <Issue>https://github.com/dotnet/runtime/issues/64127</Issue>
         </ExcludeList>
         <ExcludeList Include = "$(XunitTestBinBase)/Loader/classloader/StaticVirtualMethods/GenericContext/**">
             <Issue>https://github.com/dotnet/runtime/issues/67359</Issue>
         </ExcludeList>
+        <ExcludeList Include="$(XunitTestBinBase)/Interop/StructMarshalling/PInvoke/NestedStruct/**">
+            <Issue>https://github.com/dotnet/runtime/issues/91388</Issue>
+        </ExcludeList>
+        <ExcludeList Include="$(XunitTestBinBase)/Interop/NativeLibrary/MainProgramHandle/MainProgramHandleTests/**">
+            <Issue>https://github.com/dotnet/runtime/issues/91388</Issue>
+        </ExcludeList>
+        <ExcludeList Include="$(XunitTestBinBase)/Interop/DllImportSearchPaths/DllImportSearchPathsTest/**">
+            <Issue>https://github.com/dotnet/runtime/issues/91388</Issue>
+        </ExcludeList>
     </ItemGroup>
 
     <ItemGroup Condition="'$(TargetOS)' == 'android' And '$(TargetArchitecture)' == 'arm64'">